Skill v1.0.1
currentAutomated scan100/100+5 new
name: typescript-advanced-types description: Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects. metadata: version: "1.0.1"
TypeScript Advanced Types
Comprehensive guidance for mastering TypeScript's advanced type system including generics, conditional types, mapped types, template literal types, and utility types for building robust, type-safe applications.
When to Use This Skill
- Building type-safe libraries or frameworks
- Creating reusable generic components
- Implementing complex type inference logic
- Designing type-safe API clients
- Building form validation systems
- Creating strongly-typed configuration objects
- Implementing type-safe state management
- Migrating JavaScript codebases to TypeScript
Core Concepts
1. Generics
Purpose: Create reusable, type-flexible components while maintaining type safety.
Basic Generic Function:
function identity<T>(value: T): T {return value;}const num = identity<number>(42); // Type: numberconst str = identity<string>("hello"); // Type: stringconst auto = identity(true); // Type inferred: boolean
Generic Constraints:
interface HasLength {length: number;}function logLength<T extends HasLength>(item: T): T {console.log(item.length);return item;}logLength("hello"); // OK: string has lengthlogLength([1, 2, 3]); // OK: array has lengthlogLength({ length: 10 }); // OK: object has length// logLength(42); // Error: number has no length
Multiple Type Parameters:
function merge<T, U>(obj1: T, obj2: U): T & U {return { ...obj1, ...obj2 };}const merged = merge({ name: "John" }, { age: 30 });// Type: { name: string } & { age: number }
2. Conditional Types
Purpose: Create types that depend on conditions, enabling sophisticated type logic.
Basic Conditional Type:
type IsString<T> = T extends string ? true : false;type A = IsString<string>; // truetype B = IsString<number>; // false
Extracting Return Types:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;function getUser() {return { id: 1, name: "John" };}type User = ReturnType<typeof getUser>;// Type: { id: number; name: string; }
Distributive Conditional Types:
type ToArray<T> = T extends any ? T[] : never;type StrOrNumArray = ToArray<string | number>;// Type: string[] | number[]
Nested Conditions:
type TypeName<T> = T extends string? "string": T extends number? "number": T extends boolean? "boolean": T extends undefined? "undefined": T extends Function? "function": "object";type T1 = TypeName<string>; // "string"type T2 = TypeName<() => void>; // "function"
3. Mapped Types
Purpose: Transform existing types by iterating over their properties.
Basic Mapped Type:
type Readonly<T> = {readonly [P in keyof T]: T[P];};interface User {id: number;name: string;}type ReadonlyUser = Readonly<User>;// Type: { readonly id: number; readonly name: string; }
Optional Properties:
type Partial<T> = {[P in keyof T]?: T[P];};type PartialUser = Partial<User>;// Type: { id?: number; name?: string; }
Key Remapping:
type Getters<T> = {[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];};interface Person {name: string;age: number;}type PersonGetters = Getters<Person>;// Type: { getName: () => string; getAge: () => number; }
Filtering Properties:
type PickByType<T, U> = {[K in keyof T as T[K] extends U ? K : never]: T[K];};interface Mixed {id: number;name: string;age: number;active: boolean;}type OnlyNumbers = PickByType<Mixed, number>;// Type: { id: number; age: number; }
4. Template Literal Types
Purpose: Create string-based types with pattern matching and transformation.
Basic Template Literal:
type EventName = "click" | "focus" | "blur";type EventHandler = `on${Capitalize<EventName>}`;// Type: "onClick" | "onFocus" | "onBlur"
String Manipulation:
type UppercaseGreeting = Uppercase<"hello">; // "HELLO"type LowercaseGreeting = Lowercase<"HELLO">; // "hello"type CapitalizedName = Capitalize<"john">; // "John"type UncapitalizedName = Uncapitalize<"John">; // "john"
Path Building:
type Path<T> = T extends object? {[K in keyof T]: K extends string ? `${K}` | `${K}.${Path<T[K]>}` : never;}[keyof T]: never;interface Config {server: {host: string;port: number;};database: {url: string;};}type ConfigPath = Path<Config>;// Type: "server" | "database" | "server.host" | "server.port" | "database.url"
5. Utility Types
Built-in Utility Types:
// Partial<T> - Make all properties optionaltype PartialUser = Partial<User>;// Required<T> - Make all properties requiredtype RequiredUser = Required<PartialUser>;// Readonly<T> - Make all properties readonlytype ReadonlyUser = Readonly<User>;// Pick<T, K> - Select specific propertiestype UserName = Pick<User, "name" | "email">;// Omit<T, K> - Remove specific propertiestype UserWithoutPassword = Omit<User, "password">;// Exclude<T, U> - Exclude types from uniontype T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"// Extract<T, U> - Extract types from uniontype T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"// NonNullable<T> - Exclude null and undefinedtype T3 = NonNullable<string | null | undefined>; // string// Record<K, T> - Create object type with keys K and values Ttype PageInfo = Record<"home" | "about", { title: string }>;
Detailed worked examples and patterns
Detailed sections (starting with ## Advanced Patterns) live in references/details.md. Read that file when the navigation summary above is insufficient.
Best Practices
- Use `unknown` over `any`: Enforce type checking
- Prefer `interface` for object shapes: Better error messages
- Use `type` for unions and complex types: More flexible
- Leverage type inference: Let TypeScript infer when possible
- Create helper types: Build reusable type utilities
- Use const assertions: Preserve literal types
- Avoid type assertions: Use type guards instead
- Document complex types: Add JSDoc comments
- Use strict mode: Enable all strict compiler options
- Test your types: Use type tests to verify type behavior
Type Testing
// Type assertion teststype AssertEqual<T, U> = [T] extends [U]? [U] extends [T]? true: false: false;type Test1 = AssertEqual<string, string>; // truetype Test2 = AssertEqual<string, number>; // falsetype Test3 = AssertEqual<string | number, string>; // false// Expect error helpertype ExpectError<T extends never> = T;// Example usagetype ShouldError = ExpectError<AssertEqual<string, number>>;
Common Pitfalls
- Over-using `any`: Defeats the purpose of TypeScript
- Ignoring strict null checks: Can lead to runtime errors
- Too complex types: Can slow down compilation
- Not using discriminated unions: Misses type narrowing opportunities
- Forgetting readonly modifiers: Allows unintended mutations
- Circular type references: Can cause compiler errors
- Not handling edge cases: Like empty arrays or null values
Performance Considerations
- Avoid deeply nested conditional types
- Use simple types when possible
- Cache complex type computations
- Limit recursion depth in recursive types
- Use build tools to skip type checking in production