TY

typescript-patterns

Apply advanced TypeScript patterns like branded types, generics, and conditional type constraints.

Install

mkdir -p .claude/skills/typescript-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16489" && unzip -o skill.zip -d .claude/skills/typescript-patterns && rm skill.zip

Installs to .claude/skills/typescript-patterns

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Write precise TypeScript — generic constraints, conditional types, mapped types, template literal types, branded/nominal types, type narrowing, satisfies operator, and utility type composition. Use when asked about "TypeScript generics", "conditional type", "mapped type", "infer keyword", "branded type", "nominal typing", "template literal type", "satisfies", "utility types", "type narrowing", "discriminated union", "type predicate", "TypeScript strict mode", "keyof typeof", or "TypeScript advanced patterns". Do NOT use for: React-specific TypeScript — see frontend-patterns. Do NOT use for: API type generation — see api-design.
635 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Implement branded/nominal types for compile-time ID distinction
  • Model complex state machines with discriminated unions
  • Apply generic constraints to function parameters
  • Extract types using conditional types and the `infer` keyword
  • Transform types with mapped types
  • Define string patterns with template literal types

How it works

The skill provides examples and guidance on using advanced TypeScript features like branded types, discriminated unions, and generic constraints to improve type safety and expressiveness.

Inputs & outputs

You give it
TypeScript code requiring type safety or advanced type constructs
You get back
TypeScript code demonstrating precise type usage, such as branded types, discriminated unions, or generic constraints

When to use typescript-patterns

  • Implement branded types
  • Write complex generic constraints
  • Refactor type narrowing

About this skill

When to Use

  • Use when: types are too broad (any, as unknown, as SomeType casts)
  • Use when: building a reusable library or SDK that needs precise generics
  • Use when: needing runtime-safe IDs (userId vs orderId confusion)
  • Use when: modeling complex state machines with discriminated unions
  • Do NOT use for: React component prop types — see frontend-patterns
  • Do NOT use for: Zod schema ↔ type sync — that's in api-design

Branded / Nominal Types

// Prevents mixing IDs from different domains at compile time
type Brand<T, B extends string> = T & { readonly _brand: B };

type UserId  = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;

function getUser(id: UserId): Promise<User> { ... }

// Create branded values at system boundaries
const userId  = '123' as UserId;
const orderId = '456' as OrderId;

getUser(userId);    // ✅
getUser(orderId);   // ❌ TypeScript error — OrderId is not UserId
getUser('123');     // ❌ string is not UserId

Discriminated Unions

// Exhaustive state modeling — TypeScript checks all cases
type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error';   error: Error };

function render<T>(state: AsyncState<T>) {
  switch (state.status) {
    case 'idle':    return <Idle />;
    case 'loading': return <Spinner />;
    case 'success': return <Data data={state.data} />;
    case 'error':   return <ErrorMsg error={state.error} />;
    // TypeScript error if a case is missing (with noImplicitReturns)
  }
}

Generic Constraints

// Constrain T to objects with a known shape
function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
  return items.map(item => item[key]);
}

const names = pluck([{ name: 'Alice', age: 30 }], 'name'); // string[]
pluck([{ name: 'Alice' }], 'missing'); // ❌ TypeScript error

// Constrain to objects with an id field
function findById<T extends { id: string }>(items: T[], id: string): T | undefined {
  return items.find(i => i.id === id);
}

Conditional Types + infer

// Extract return type of async function
type Awaited<T> = T extends Promise<infer R> ? R : T;

type Result = Awaited<Promise<string>>;  // string

// Extract first argument of a function
type FirstArg<T extends (...args: any[]) => any> =
  T extends (first: infer F, ...rest: any[]) => any ? F : never;

type F = FirstArg<(id: string, limit: number) => void>;  // string

// Distributive conditional types
type Nullable<T> = T extends null | undefined ? never : T;
type Clean = Nullable<string | null | undefined | number>;  // string | number

Mapped Types

// Make all fields optional and readonly
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

// Create event handler map from event union
type EventHandlers<T extends { type: string }> = {
  [K in T['type']]: (event: Extract<T, { type: K }>) => void;
};

type AppEvent =
  | { type: 'USER_LOGIN';  userId: string }
  | { type: 'PAGE_VIEW';   path: string }
  | { type: 'PURCHASE';    amount: number };

const handlers: EventHandlers<AppEvent> = {
  USER_LOGIN: ({ userId }) => console.log(userId),
  PAGE_VIEW:  ({ path })   => analytics.track(path),
  PURCHASE:   ({ amount }) => metrics.record(amount),
};

Template Literal Types

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
type Endpoint = `/${string}`;
type Route = `${HttpMethod} ${Endpoint}`;

const routes: Route[] = ['GET /users', 'POST /orders'];
const invalid: Route = 'FETCH /data';  // ❌ TypeScript error

// CSS property builder
type CSSProperty = `${string}-${'color' | 'size' | 'weight'}`;

satisfies Operator (TS 4.9+)

// satisfies: validate type without widening — keeps literal inference
const config = {
  port: 3000,
  env: 'production',
  db: { host: 'localhost', port: 5432 },
} satisfies Partial<AppConfig>;

config.port;  // type: number (not widened to AppConfig['port'])
config.env;   // type: 'production' (literal, not string)

// vs `as AppConfig` — that would lose literal types
// vs `: AppConfig` — that would accept missing fields

Type Guards

// User-defined type guard
function isApiError(error: unknown): error is ApiError {
  return typeof error === 'object' && error !== null
    && 'code' in error && 'message' in error;
}

try {
  await api.call();
} catch (err) {
  if (isApiError(err)) {
    console.log(err.code);    // typed as ApiError
  } else {
    throw err;
  }
}

// Assertion function (throws instead of returning false)
function assertDefined<T>(val: T | undefined, name: string): asserts val is T {
  if (val === undefined) throw new Error(`${name} must be defined`);
}

Anti-Fake-Pass Rules

Before claiming TypeScript types are production-quality, you MUST show:

  • strict: true enabled — no partial strict mode
  • No any in public APIs — use unknown + type guards instead
  • No unchecked as T casts — add runtime assertion or type guard
  • IDs use branded types — no mixing of string ID domains
  • State machines use discriminated unions — no boolean flag soup
  • All switch statements over discriminated unions are exhaustive

Reference: gates/anti-fake-pass-gate.md

When not to use it

  • For React-specific TypeScript patterns
  • For API type generation
  • For Zod schema to type synchronization

Prerequisites

TypeScript ≥ 5.0strict: true compiler option

Limitations

  • Requires TypeScript 5.0 or newer
  • Requires `strict: true` in tsconfig.json
  • Does not cover React-specific prop types

How it compares

This skill offers specific TypeScript patterns to achieve compile-time type safety and reduce reliance on 'any' or unsafe casts, unlike generic TypeScript usage that might lead to broader types.

Compared to similar skills

typescript-patterns side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
typescript-patterns (this skill)01moReviewAdvanced
typescript-expert106moReviewAdvanced
agent-coder36moNo flagsIntermediate
functional32moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry