Yeah but just because types exist at compile time doesn't mean they exist at run time.
For instance with Generics in Java a List<String> is the same as a List<Integer> at run time, the compiler can enforce rules that let you add a String to one but not add a String to the other but the runtime has no idea. This has various negative consequences but it also let them retrofit generic collections on top of the old collection implementation in Java unlike the disaster in .NET where both had to coexist for years.
Similarly C compiles to machine code and in machine code there are just memory locations and registers, types are implicit in how you use those things but not spelled out explicitly. C++ does have RTTI but is one of the many open pits, like Exceptions, in C++.
Typescript types are the same way, once the compiler has done its type checking you know the code is going to behave according to the type system even if the types have been "erased".
Depends on the situation. If you just make an ArrayList<X> (for some specific class X) you can call getClass() on that object and see it is an ArrayList but you cannot find out about the X.
If you make an ArrayListX that is not generic but extends ArrayList<X> it is possible to see the type parameter that was extended, the same is true for implementations.
There are other kinds of type unerasure that you can use w/o the language supporting it explictly, such as you could pass the type parameter X.class into the constructor and put it in a field so that you could call some method like getContainedClass() and get a copy of X.
Now the introspection/reflection API does have support for talking about parameterized generic types that doesn't mean that information always exists at runtime.
I worked on a crazy project where I did a lot of fighting with ordinary types and parameterized types and unerasing types by rewriting the names of methods to avoid conflicts, if you have methods like
but you can't have an overload that takes two differently parameterized expressions, this lets you write Java code in a lisp-like syntax that can be metaprogrammed on:
that project got me thinking a lot about the various ways types manifest in Java and I made the discovery that when you add Expression types you practically discover an extended type systems where there are many things that are implied by the existence of ordinary Java types.
I know how it works. The point of the topic was to have type information available, so we can use it for things like dynamic binding. No one asks for the runtime to be as strict as the type system (the compiler).
BTW. I do not agree with the opinion in the topic. Since Typescript is compiled to something else (usually JS), I'd prefer Typescript to have proper annotations (there are "decorators") and compiler hooks and just use code generation for concerns like (de)serialization.
For instance with Generics in Java a List<String> is the same as a List<Integer> at run time, the compiler can enforce rules that let you add a String to one but not add a String to the other but the runtime has no idea. This has various negative consequences but it also let them retrofit generic collections on top of the old collection implementation in Java unlike the disaster in .NET where both had to coexist for years.
Similarly C compiles to machine code and in machine code there are just memory locations and registers, types are implicit in how you use those things but not spelled out explicitly. C++ does have RTTI but is one of the many open pits, like Exceptions, in C++.
Typescript types are the same way, once the compiler has done its type checking you know the code is going to behave according to the type system even if the types have been "erased".