upvote
Two things to note:

1. TypeScript doesn't aim to have a sound type system. i.e. there may be things the type system accepts that are actually unsafe.

2. this is more of an issue with mutation. If those properties were marked `readonly`, then the assignment of y.a wouldn't work at all. You can also encapsulate mutation behind functions with your intended types.

I tend to write TypeScript in a "functional" or "immutable" way, and in this case, most soundness issues come from things like array index access, which can't really be solved without dependent types anyway.

With that said, TypeScript still gets one quite far *despite* soundness not being a goal of the type system. The problem is that writing imperative, mutable code will make you go through (intentionally!) unsound covariance of types. Similar issues exist for code with side effects, since TypeScript has no way to encode effects in the type system. This is why some language communities settle on ideas like "functional core, imperative shell", where the ultimate goal is absolute minimum amount of code involved in side effects and mutation, while everything else is designed to be easy to test (and, ideally, expressible with a sound subset of your type system).

reply