Typescript, as a counterexample, doesn't need GADTs because it has first-class union support + nice type filtering. There's a bit of manual tagging that's needed but the ergonomics are both easy to understand and more flexible (not to mention supporting even other usage patterns).
type Term = {kind: 'lit', value: number} | {kind: 'pair', left: Term, right: Term};
function pair(left: Term, right: Term): Term & {kind: 'pair'} {
return {kind: 'pair', left, right};
}
function lit(n: number): Term & {kind: 'lit'} {
return {kind: 'lit', value: n};
}
let t: Term = pair(
pair(lit(1), lit(2)),
lit(3)
);