Depends on what you mean by "good abstraction". If I wish to use sum types to represent discriminated unions and parametric polymorphic types then yes its better to make sure the type "sets" don't intersect.
I wouldn't really consider this encoding special though - its standard practice e.g see Redux. The usage syntax could be better, but its very much a native, commonly accepted practice that works well.
If however I want to use unions for other things, like simple unions of `string | number` I can do that too. For example, I can also describe overlapping records of "options" where specifying one option means you have to specify another, and I can model that without nesting the option subsets. I can't do that with sum types.
Its unfortunate but lots of JS libraries do mix parametric types with their parameters e.g. `T | Promise<T>` means that Promise<Promise<T>> is the same as Promise<T>, however at least we can model that in the type system.
TypeScript is worse at all things involving parametric polymorphism, thats true. Mainly due to lack of higher kinded types, but also due to the bad modeling habits of parametric things built into the JS language (not just promises - look at array concat). But thats why I qualified my statement with "if you look at sum types in isolation"
With records, though, its just way ahead - so much so that I'm bothered by the primitive built in records in most other languages. Its great that row polymorphism is a nicer way to handle records, but I need the power too, and TS gives me that.