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.zipInstalls 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.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
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 SomeTypecasts) - 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: trueenabled — no partial strict mode - No
anyin public APIs — useunknown+ type guards instead - No unchecked
as Tcasts — add runtime assertion or type guard - IDs use branded types — no mixing of
stringID domains - State machines use discriminated unions — no
booleanflag soup - All
switchstatements 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
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.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| typescript-patterns (this skill) | 0 | 1mo | Review | Advanced |
| typescript-expert | 10 | 6mo | Review | Advanced |
| agent-coder | 3 | 6mo | No flags | Intermediate |
| functional | 3 | 2mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by yanacuti1121
View all by yanacuti1121 →You might also like
typescript-expert
davila7
TypeScript and JavaScript expert with deep knowledge of type-level programming, performance optimization, monorepo management, migration strategies, and modern tooling. Use PROACTIVELY for any TypeScript/JavaScript issues including complex type gymnastics, build performance, debugging, and architectural decisions. If a specialized expert is a better fit, I will recommend switching and stop.
agent-coder
ruvnet
Agent skill for coder - invoke with $agent-coder
functional
citypaul
Functional programming patterns with immutable data. Use when writing logic or data transformations.
modern-javascript-patterns
sickn33
Master ES6+ features including async/await, destructuring, spread operators, arrow functions, promises, modules, iterators, generators, and functional programming patterns for writing clean, efficient JavaScript code. Use when refactoring legacy code, implementing modern patterns, or optimizing JavaScript applications.
migrate-honcho-ts
plastic-labs
Migrates Honcho TypeScript SDK code from v1.6.0 to v2.0.0. Use when upgrading @honcho-ai/sdk, fixing breaking changes after upgrade, or when errors mention removed APIs like .core, getConfig, observations, or snake_case properties.
agent-implementer-sparc-coder
ruvnet
Agent skill for implementer-sparc-coder - invoke with $agent-implementer-sparc-coder