From claude-initial-setup
Master TypeScript generics for reusable, type-safe abstractions. Use when the user works with generic constraints, conditional types, mapped types, the infer keyword, utility types, recursive types, or needs help building type-safe libraries, APIs, or data structures.
npx claudepluginhub versoxbt/claude-initial-setup --plugin claude-initial-setupThis skill uses the workspace's default tool permissions.
Build powerful, reusable type abstractions with generics. Generics let you write
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Build powerful, reusable type abstractions with generics. Generics let you write code that works across types while preserving full type safety.
Constrain type parameters to ensure they have required properties.
// Basic constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name"); // string
// getProperty(user, "email"); // Compile error
// Constraint with interface
interface HasId {
id: string;
}
function findById<T extends HasId>(items: readonly T[], id: string): T | undefined {
return items.find((item) => item.id === id);
}
// Multiple constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
Types that choose a branch based on a condition, like a type-level ternary.
// Basic conditional
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
// Distributive conditional types (distributes over unions)
type NonNullable<T> = T extends null | undefined ? never : T;
type C = NonNullable<string | null | undefined>; // string
// Extract and Exclude
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type Numbers = Extract<string | number | boolean, number>; // number
type WithoutBool = Exclude<string | number | boolean, boolean>; // string | number
// Conditional return types
function process<T extends string | number>(
value: T
): T extends string ? string[] : number {
if (typeof value === "string") {
return value.split("") as T extends string ? string[] : number;
}
return (value * 2) as T extends string ? string[] : number;
}
Transform every property of an existing type.
// Make all properties optional
type Partial<T> = { [K in keyof T]?: T[K] };
// Make all properties required
type Required<T> = { [K in keyof T]-?: T[K] };
// Make all properties readonly
type Readonly<T> = { readonly [K in keyof T]: T[K] };
// Remap keys with `as`
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person { name: string; age: number }
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }
// Filter properties by value type
type PickByType<T, V> = {
[K in keyof T as T[K] extends V ? K : never]: T[K];
};
type StringProps = PickByType<Person, string>;
// { name: string }
Extract types from inside other types within conditional type clauses.
// Extract return type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type R = ReturnType<() => string>; // string
// Extract promise value
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type V = Awaited<Promise<Promise<number>>>; // number
// Extract array element
type ElementOf<T> = T extends readonly (infer E)[] ? E : never;
type E = ElementOf<string[]>; // string
// Extract function parameters
type FirstParam<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;
type P = FirstParam<(name: string, age: number) => void>; // string
// Infer from template literals
type ParseRoute<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? Param | ParseRoute<Rest>
: T extends `${infer _Start}:${infer Param}`
? Param
: never;
type Params = ParseRoute<"/users/:userId/posts/:postId">;
// "userId" | "postId"
Combine built-in and custom utility types for real-world scenarios.
// Updatable entity: id is required and readonly, rest is partial
type Updatable<T extends { id: string }> = Readonly<Pick<T, "id">> &
Partial<Omit<T, "id">>;
interface User {
id: string;
name: string;
email: string;
role: "admin" | "user";
}
type UserUpdate = Updatable<User>;
// { readonly id: string; name?: string; email?: string; role?: "admin" | "user" }
// Deep partial
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
// StrictOmit that validates the key exists
type StrictOmit<T, K extends keyof T> = Omit<T, K>;
// Record with specific keys
type ApiEndpoints = Record<"getUser" | "listUsers" | "createUser", string>;
Types that reference themselves for tree structures and deep transformations.
// JSON type
type Json =
| string
| number
| boolean
| null
| Json[]
| { [key: string]: Json };
// Tree structure
interface TreeNode<T> {
value: T;
children: ReadonlyArray<TreeNode<T>>;
}
// Deep readonly
type DeepReadonly<T> = T extends (infer E)[]
? ReadonlyArray<DeepReadonly<E>>
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
// Path type for nested access
type Path<T, K extends keyof T = keyof T> = K extends string
? T[K] extends object
? K | `${K}.${Path<T[K]>}`
: K
: never;
interface Config {
db: { host: string; port: number };
cache: { ttl: number };
}
type ConfigPath = Path<Config>; // "db" | "cache" | "db.host" | "db.port" | "cache.ttl"
Over-generic code -- Do not add type parameters when a concrete type suffices. Generics add cognitive load; use them only when you need reuse across multiple types.
// BAD: unnecessary generic
function greet<T extends string>(name: T): string { return `Hi ${name}`; }
// GOOD: concrete type
function greet(name: string): string { return `Hi ${name}`; }
Using any as a constraint -- Prefer unknown or a specific interface. extends any
provides no safety.
Deeply nested conditional types -- If a conditional type needs more than 3 levels of nesting, consider breaking it into named helper types for readability.
Ignoring distributive behavior -- Conditional types distribute over unions by default.
Wrap in [T] to prevent distribution when you need to treat the union as a whole:
type IsUnion<T> = [T] extends [infer U] ? ([U] extends [T] ? false : true) : never;
| Concept | Syntax | Purpose |
|---|---|---|
| Constraint | T extends U | Limit what T can be |
| Conditional | T extends U ? A : B | Branch on type |
| Mapped | { [K in keyof T]: ... } | Transform all props |
| Key remapping | as in mapped types | Rename/filter keys |
| infer | T extends F<infer U> | Extract inner type |
| Recursive | Self-referencing type | Trees, deep transforms |
| Distributive | Default on naked T | Applies to each union member |