TypeScript Generic Constraints in Depth: `extends`, `keyof`, and the Patterns That Prevent Runtime Errors
TypeScript Generic Constraints in Depth: extends , keyof , and the Patterns That Prevent Runtime Errors This article was written with the assistance of AI, under human supervision and review. Most TypeScript runtime errors stem from unconstrained generics that accept anything and crash on nothing. Teams write function get<T>(obj: T, key: string) and ship code that compiles cleanly but throws Cannot read property 'undefined' of undefined in production. The compiler stays silent because the generic accepts any type and the key accepts any string—no constraint exists to prove the key belongs to the object. Generic constraints solve this by restricting what types a generic parameter can accept. The extends keyword establishes a boundary—the generic must satisfy a specific shape. The keyof operator extracts valid keys from that shape. Together they form a type-level contract that makes illegal property access unrepresentable. The corrected signature function get<T, K extends keyof T>(obj: T, key: K): T[K] proves at compile time that key exists on obj , eliminating the entire class of property-access errors. This distinction is critical. Unconstrained generics provide no safety beyond what any offers. Constrained generics encode domain rules directly into the type system, shifting entire categories of bugs left from runtime to compile time. The patterns that follow demonstrate how production codebases use extends and keyof to build type-safe APIs that fail fast during development instead of silently in production. Key Takeaways Generic constraints with extends restrict type parameters to specific shapes, preventing the compiler from accepting types that would cause runtime failures. The keyof operator extracts object keys as a union type, enabling type-safe property access when combined with extends keyof constraints. Combining T extends SomeType with K extends keyof T creates a compile-time proof that a key exists on an object, eliminating property-access errors. Conditi