Back

Typescript Advanced Types

Coding98.4K installs

What it does

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.

Install

npx skills add https://github.com/wshobson/agents --skill typescript-advanced-types

Website

www.skills.sh/wshobson/agents/typescript-advanced-types

Details

From the skill’s SKILL.md or README, by its authors. View the original

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

  • 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 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

  • 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
See all
  • Coding

    Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.

    npx skills add https://github.com/mattpocock/skills --skill improve-codebase-architecture
    1.2M installs
  • Coding

    React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data…

    npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices
    881K installs
  • Coding

    Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes: Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel…

    npx skills add https://github.com/mattpocock/skills --skill code-review
    869.3K installs
  • Coding

    Use when you need to resolve an in-progress git merge/rebase conflict.

    npx skills add https://github.com/mattpocock/skills --skill resolving-merge-conflicts
    551.2K installs

Skills are shared by members and not reviewed by us. Read a skill’s code before you install it.