@tank/typescript-generics
1.0.0Description
Advanced TypeScript generics covering constraints, conditional and mapped types, template literal types, infer, utility types, branded types, discriminated unions, variance, and real-world generic patterns.
Triggered by
TypeScript genericsconditional typemapped typeinferutility typesbranded type
Download
Verified
tank install @tank/typescript-genericsTypeScript Generics
Core Philosophy
- Generics are functions for types -- A generic parameter is a type-level variable. Pass types in, get types out. Think of
<T>as the same kind of abstraction as(x)in value-level code. - Constrain early, infer often -- Apply the tightest constraint that satisfies the use case via
extends. Let TypeScript infer the rest. Explicit type arguments are a code smell when inference works. - Prefer composition over recursion -- Compose built-in utility types and simple conditionals. Recursive types hit the 50-depth limit and destroy IDE performance.
- Types should disappear at runtime -- The best generic code compiles to the same JavaScript as hand-written code. If generics force runtime checks, redesign the type.
- Read the error from the bottom -- TypeScript error messages for generics are deeply nested. The actual constraint violation is at the bottom of the stack.
Quick-Start: Common Problems
"I need a function that works on multiple types"
- Add a type parameter:
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> - Constrain with
extends-- usekeyof, interfaces, or unions - Let inference fill in
Tfrom the call site argument -> Seereferences/generics-fundamentals.md
"Which utility type do I need?"
| Goal | Utility |
|---|---|
| Make all props optional | Partial<T> |
| Make all props required | Required<T> |
| Select subset of props | Pick<T, K> |
| Remove specific props | Omit<T, K> |
| Object from key-value union | Record<K, V> |
| Remove members from union | Exclude<U, M> |
| Keep members from union | Extract<U, M> |
| Function return type | ReturnType<F> |
| Function parameter types | Parameters<F> |
| Unwrap Promise | Awaited<T> |
-> See references/utility-types.md |
"My conditional type doesn't distribute correctly"
- Wrap both sides in
[T] extends [U]to disable distribution - Use
neverto filter union members:T extends U ? T : never - Remember: distribution only happens on naked type parameters
-> See
references/conditional-types.md
"Type instantiation is excessively deep"
- Reduce recursive depth -- flatten with tail-call patterns or iterative mapped types
- Add explicit type annotations at intermediate steps
- Break complex types into smaller named aliases
- Use
NoInfer<T>(TS 5.4+) to block unwanted inference sites -> Seereferences/errors-performance.md
"I want types that prevent invalid states"
- Use discriminated unions with a literal
kind/typetag - Add branded types for domain primitives (UserId, Email)
- Model state machines as discriminated unions
-> See
references/branded-discriminated.md
Decision Trees
Generic vs Overload vs Union
| Signal | Approach |
|---|---|
| Return type depends on input type | Generic |
| Few fixed input-output pairs | Overloads |
| Accept several types, same return | Union parameter |
| Need to relate multiple params | Generic with multiple type params |
Mapped vs Conditional vs Template Literal
| Need | Type Feature |
|---|---|
| Transform every property of an object | Mapped type |
| Branch on a type condition | Conditional type |
| Build string types from parts | Template literal type |
| Extract inner type from wrapper | infer in conditional |
| Remap object keys | Mapped type with as clause |
Constraint Strategy
| Scenario | Constraint |
|---|---|
| Must have specific property | T extends { prop: Type } |
| Must be object key | K extends keyof T |
| Must be callable | T extends (...args: any[]) => any |
| Must be constructable | T extends abstract new (...args: any[]) => any |
| Must be a string subtype | T extends string |
| Array element type needed | T extends readonly any[] then T[number] |
Reference Index
| File | Contents |
|---|---|
references/generics-fundamentals.md | Type parameters, constraints, defaults, inference, generic functions, classes, and interfaces |
references/conditional-types.md | Conditional syntax, distributive behavior, infer keyword, never filtering, and non-distributive patterns |
references/mapped-types.md | Property iteration, modifier removal (-readonly, -?), key remapping with as, homomorphic mappings |
references/template-literal-types.md | String type construction, union expansion, intrinsic string types, event emitter patterns |
references/utility-types.md | All built-in utility types with implementation, use cases, and composition patterns |
references/branded-discriminated.md | Branded/opaque types, discriminated unions, type narrowing, type guards, assertions, satisfies |
references/variance-advanced.md | Covariance, contravariance, in/out annotations, generic classes, higher-kinded type emulation |
references/real-world-patterns.md | Builder pattern, factory, registry, type-safe event emitter, state machine, Zod/tRPC patterns |
references/errors-performance.md | Common error messages, recursive type limits, performance tuning, NoInfer, debugging strategies |