Zod is by far the most ergonomic way to express those ideas in TypeScript these days. I miss it when writing code in other languages. The friction with the rest of the ecosystem is real, though. Most code out there expects you to handle errors with exceptions. I get the impression that polymorphic return types could get in the way of JSC/V8/SpiderMonkey's JIT, but I haven't measured it and I'm not sure of the actual…
I haven't done a lot of Typescript, but I've done at least a couple of month's worth now, and every time I have to type "as" my inner Haskell programmer screams. If I could add one feature to Typescript it would be something like "as" that actually validates the result against the type system and can fail. Unfortunately, that's way, way easier said than done. It's the bad type of keyword that has unbounded runtime co…
If you have a validator function `function isSomeSpecificType(obj: unknown): boolean` you make it a Type Guard by changing the return type to be the type assertion you need: `function isSomeSpecificType(obj: unknown): obj is SomeSpecificType`. Typescript's narrowing is pretty good about using Type Guards to good advantage.