Advanced TypeScript
Master advanced TypeScript - generics, conditional types, mapped types, template literals, and utility types to write type-safe, expressive code without any.
skill: Advanced TypeScript category: Web Development tags: [TypeScript, Generics, Type Safety, Utility Types, JavaScript] readingTime: 7
TypeScript's type system is a programming language in itself - you can compute types, not just annotate them. Advanced features like conditional types and mapped types eliminate entire categories of runtime errors. The goal is to encode your domain constraints in the type system so impossible states become unrepresentable - errors caught at compile time, not in production.
Workflow
- Write effective generics with constraintsGeneric functions work with any type - constraints limit which types are allowed, enabling type-safe access to properties within the generic.
- Use conditional typesConditional types compute different types based on conditions - like if-else at the type level - enabling expressive, context-sensitive type inference.
- Build mapped typesMapped types transform every property in a type - making all optional, readonly, or changing property types - enabling systematic type transformations.
- Use template literal typesTemplate literal types enable string manipulation at the type level - generating event names, CSS property types, or API endpoint strings with full type safety.
- Model domains with discriminated unionsDiscriminated unions make impossible states unrepresentable - instead of nullable fields and runtime checks, the type system enforces valid states.
Output Format
Advanced TypeScript: generics with constraints, conditional types, mapped types, template literals, and discriminated unions.
// Type-safe patterns:
// Generics: <T extends Constraint>(arg: T): ReturnType
// Conditional: T extends X ? Y : Z
// Mapped: { [K in keyof T]: Transform<T[K]> }
// Discriminated union: type T = { kind: 'a', ... } | { kind: 'b', ... }
// Utility types: Partial, Required, Readonly, Pick, Omit, RecordExamples
Edge Cases & Gotchas
- Type widening - const x = 'hello' gets type 'hello' (literal); let x = 'hello' gets type string (widened). Use as const to preserve literal types: const config = { env: 'prod' } as const → type is { env: 'prod' }.
- Excessive type complexity - TypeScript has a type instantiation depth limit - deeply recursive conditional types can hit it. If you see 'Type instantiation is excessively deep', simplify the type or use an interface instead.
- Declaration merging - Interfaces merge when declared twice; types don't. Use interface for public API types (so consumers can extend them) and type for internal computed types.
- Strict mode gotchas - Enabling strictNullChecks later in a project creates hundreds of errors. Start with strict: true from day one. Migrating a large codebase to strict mode takes weeks.
When to Break These Rules
- Use type: any or unknown with narrowing for external data (API responses, user input, JSON.parse) - these legitimately don't have known types at compile time. Validate with Zod or Valibot at runtime.
- Use // @ts-ignore or @ts-expect-error sparingly for type system limitations (e.g., a well-known library that's not typed correctly) - prefer proper typing but don't block progress for minor edge cases.
Reference Files
https://www.typescriptlang.org/docs/handbook/2/types-from-types.htmlhttps://type-level-typescript.com/