Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    wshobson

    typescript-advanced-types

    wshobson/typescript-advanced-types
    Coding
    28,185
    1 installs

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications...

    SKILL.md

    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: number
    const str = identity<string>("hello"); // Type: string
    const 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 length
    logLength([1, 2, 3]); // OK: array has length
    logLength({ 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>; // true
    type 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 optional
    type PartialUser = Partial<User>;
    
    // Required<T> - Make all properties required
    type RequiredUser = Required<PartialUser>;
    
    // Readonly<T> - Make all properties readonly
    type ReadonlyUser = Readonly<User>;
    
    // Pick<T, K> - Select specific properties
    type UserName = Pick<User, "name" | "email">;
    
    // Omit<T, K> - Remove specific properties
    type UserWithoutPassword = Omit<User, "password">;
    
    // Exclude<T, U> - Exclude types from union
    type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
    
    // Extract<T, U> - Extract types from union
    type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
    
    // NonNullable<T> - Exclude null and undefined
    type T3 = NonNullable<string | null | undefined>; // string
    
    // Record<K, T> - Create object type with keys K and values T
    type 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

    1. Use unknown over any: Enforce type checking
    2. Prefer interface for object shapes: Better error messages
    3. Use type for unions and complex types: More flexible
    4. Leverage type inference: Let TypeScript infer when possible
    5. Create helper types: Build reusable type utilities
    6. Use const assertions: Preserve literal types
    7. Avoid type assertions: Use type guards instead
    8. Document complex types: Add JSDoc comments
    9. Use strict mode: Enable all strict compiler options
    10. Test your types: Use type tests to verify type behavior

    Type Testing

    // Type assertion tests
    type AssertEqual<T, U> = [T] extends [U]
      ? [U] extends [T]
        ? true
        : false
      : false;
    
    type Test1 = AssertEqual<string, string>; // true
    type Test2 = AssertEqual<string, number>; // false
    type Test3 = AssertEqual<string | number, string>; // false
    
    // Expect error helper
    type ExpectError<T extends never> = T;
    
    // Example usage
    type ShouldError = ExpectError<AssertEqual<string, number>>;
    

    Common Pitfalls

    1. Over-using any: Defeats the purpose of TypeScript
    2. Ignoring strict null checks: Can lead to runtime errors
    3. Too complex types: Can slow down compilation
    4. Not using discriminated unions: Misses type narrowing opportunities
    5. Forgetting readonly modifiers: Allows unintended mutations
    6. Circular type references: Can cause compiler errors
    7. 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
    Recommended Servers
    Browser tool
    Browser tool
    DataForB2B
    DataForB2B
    Supabase
    Supabase
    Repository
    wshobson/agents
    Files