TypeScript is the strangest answer in this section. Every other language here treats a type parameter as a placeholder for a type someone will supply. TypeScript treats it as an input to a computation that produces a type, and the type level grew into a language of its own: pattern matching, recursion, string manipulation, and a depth budget that exists because no compiler can decide whether your types terminate. The same <T> syntax as Java or C#, doing a different job.
The other oddity is what sits underneath. The runtime is JavaScript, which knows nothing about any of it. Java erases for compatibility with code that predates generics; TypeScript erases because there was never anything there to keep. The foundation under all of it is structural assignability, and the comparison against the other four answers lives in Generics, Monomorphization vs Erasure.
Generics in a structural system
Why the familiar syntax means something else here.
- Generics Over a Structural Type System - a type parameter as a hole in a shape rather than a named promise
- Generic Constraints and Defaults - a shape test that pays out twice, and a separate mechanism easy to confuse with it
- Contextual Typing and Inference - inference running upward and downward at once, which is what keeps untyped callbacks alive under strict mode
- Variance Annotations, in and out - a decade without declaration-site variance, and what the annotations actually bought
The type level as a language
The part no other folder in this section has. Read these in order; each one is built out of the ones before it.
- keyof, typeof, and Indexed Access - the one-way bridge from the value world into the type world
- Mapped Types - a fold from a union of keys into an object type, with the key names and modifiers under control
- Conditional Types - an assignability test that suspends itself when the answer depends on a type variable
- Distributive Conditional Types - two square brackets decide whether the check maps over a union or tests it whole
- infer and Type-Level Pattern Matching - destructuring for types, scoped to the branch that matched
- Template Literal Types - strings stop being atoms, and the bill arrives as a cross product
- Type-Level Computation and Its Limits - Turing completeness means no termination check, so what ships is a budget
Where the types stop
- Erasure at Runtime and Type Guards - every runtime check is something a human wrote, and the language only supplies the wiring back to the checker
- The any, unknown, never Triangle - the escape hatch, the top type, and the bottom type, filed under one heading and behaving nothing alike
The rest of the language
- Structural Typing and Assignability - compatibility by shape, and the two relations underneath it
- Union and Intersection Types - combining value sets, and why reachable members move the opposite way
- Discriminated Unions and Exhaustiveness - a literal-typed tag that ordinary JavaScript comparisons can narrow
- Strict Null Checks - removing
nullfrom the value set of every other type, and why that had to ship as a flag - satisfies and const Assertions - separating checking a value against a type from adopting that type
- Declaration Files and Ambient Types - a signature with no implementation, which is both the power and the hazard
- Modules and Resolution - a compiler that never loads a module simulating somebody else’s file lookup
- Decorators - the shipped ECMAScript form, and why the experimental one is a different feature
- The Compiler API and Emit - three moving parts, and why the middle one makes type-aware tooling slow
Read from the comparative layer
- Generics, Monomorphization vs Erasure - erasure by construction against the other four answers
- Protocols and Structural Subtyping - the other structural answer, opt-in instead of default
- Reified Generics in the CLR - the opposite bargain
- Module Systems and Namespacing - runtime path search against compile-time trees
Any pages placed under this folder are auto-listed below by Quartz.