But TypeScript doesn’t have ADTs which you stated was a hard requirement. It has some other features that can achieve similar things though, so maybe that’s good enough?
Kinda nitpicky. Sure ADTs are a pattern in Typescript rather than a first-class entity, but they're an extremely well-supported pattern, exhaustiveness checking and all.
type ADT =
| { case : 'a', a : Number }
| { case : 'b', b : string }
function f (c : ADT) {
switch(c.case) {
case 'a' : return c.a
case 'b' : return Number.parseInt(c.b)
// case 'c' : return 0 // compile error
// case 'b' : return c.a // also compile error
}
}