> TypeScript’s type system is purely structural and exists only at compile time. It has no way to verify that your function actually implements what its signature claims. You can declare that a function transforms a User into a SafeUser, and as long as the return object has the required fields of SafeUser, TypeScript doesn’t care what additional properties might still be lurking in there.<p>> This is fundamentally different from languages like Rust, where the type system can actually guarantee that if you claim to return an Option<T>, you genuinely can’t return null, the compiler enforces the contract at the language level. Rust’s type system doesn’t just trust your annotations; it verifies them.<p>This design where types are present at compile-time but disappear at runtime is called type erasure, and it's extremely common. For example, Java's generics are type erased. If you have some Java class Foo<T, U>, in the bytecode it will simply become Foo, and T and U will become Object. Therefore, you cannot use runtime introspection to recover their instantiations.<p>The remark contrasting TypeScript to Rust seems a little confused. Rust also uses type erasure; types and lifetimes are checked by the compiler, then the compiler produces a native executable, which is just machine code and would not contain type information. Option<&T> could be treated as a pointer T*, because the niche optimization ensures that the Option::None variant is represented as 0 or NULL. If C code were to interact with Rust code via FFI, it would be able to pass a value of 0. However, Rust doesn't have a null value the way that it's commonly understood in languages such as Java, C#, or JavaScript, a distinguished value that denotes a "sentinel" reference that does not refer to any object. I would say that the null reference is semantically a higher-level concept, specific to these particular programming languages.<p>Philosophically, the notion of type erasure goes all the way back to Curry-style (extrinsic) typing, which is contrasted with Church-style (intrinsic) typing. For example, in Curry-style typing, the program (fun x -> x) is the identity function on all types, while in Church-style typing, each type A has its own identity function, (fun (x : A) -> x) and a program is meaningless without types.<p>Please correct me if I'm wrong or misunderstood!
It looks like the op is actually talking about structural typing vs nominal typing, which makes more sense bc Rust is nominally typed (newtype pattern, for example), whereas Typescript is structurally typed.<p>And you’re right, this has nothing to do with type erasure.
I think what the author is trying to say is that the type system of TypeScript is unsound, while Rust's type system is (hopefully) sound.