var e=[{file:`SKILL.md`,content:`---
name: typescript
description: "Comprehensive TypeScript development patterns — type system performance, compiler configuration, advanced types, type safety, async patterns, module organization, and runtime optimization."
metadata:
  category: domain
  domain: typescript
  applicability: on-demand
  inputs: [codebase, requirements]
  outputs: [type-patterns, code]
  relatedSkills: [react]
---

# TypeScript

> Comprehensive TypeScript development patterns — type system performance, compiler configuration, advanced types, type safety, async patterns, module organization, and runtime optimization. Synthesized from pproenca TypeScript rules, TypeScript 6.0 features, wshobson advanced types and modern JS patterns, and Jeffallan typescript-pro patterns.

## Mindset

Type errors are specifications, not obstacles. Every red squiggle is the compiler telling you about a contract violation BEFORE runtime. Your job is to make impossible states unrepresentable — if the type system allows an invalid value, the design is wrong.

Think in terms of: narrowing (make types more specific at each step), branding (distinguish structurally identical types by meaning), and exhaustiveness (force the compiler to verify all cases are handled).

## When to Use

**MANDATORY** for the Implementer agent on every TypeScript task. Also use when:
- Writing or reviewing TypeScript code
- Configuring \`tsconfig.json\` or compiler options
- Designing type-safe APIs, libraries, or utilities
- Optimizing type-check performance or build times

## NEVER

- **NEVER use \`as\` to silence type errors** — it hides bugs. Use type guards, assertion functions, or fix the upstream type instead. \`as\` is only acceptable for test mocks with \`as unknown as T\` pattern.
- **NEVER use \`any\` in exported signatures** — it infects every consumer. Use \`unknown\` + narrowing, generics, or explicit union types. \`any\` in implementation internals is tolerable if contained.
- **NEVER use \`!\` (non-null assertion) without a runtime guard** — it's a lie to the compiler. If you're sure it's not null, prove it with an \`if\` check or \`?? throw\`.
- **NEVER mix null and undefined semantics** — pick one convention per codebase. Prefer \`undefined\` for "not set" (matches optional properties), \`null\` for "explicitly empty" (matches DOM/JSON).
- **NEVER export mutable state as a shared type** — use \`readonly\` modifier, \`Readonly<T>\`, or \`ReadonlyArray<T>\`. Mutable shared state causes action-at-a-distance bugs that types cannot catch.
- **NEVER use \`enum\` in new code** — use \`as const\` objects or string literal unions. Enums have runtime cost, tree-shaking issues, and numeric enums allow unsafe access.
- **NEVER ignore generic constraints** — if a function works on "any array", type it as \`T extends readonly unknown[]\`, not \`T[]\`. Constraints document intent and catch misuse at call sites.

## Type System Performance

These rules prevent slow type-checking and IDE lag:

### Prefer Flat Unions Over Deep Conditionals
\`\`\`tsx
// BAD — O(n²) type checking with deep conditionals
type DeepResolve<T> = T extends Promise<infer U> ? DeepResolve<U> : T extends Array<infer V> ? DeepResolve<V>[] : T;

// GOOD — flat unions check in O(n)
type Status = "idle" | "loading" | "success" | "error";
type Result = SuccessResult | ErrorResult | PendingResult;
\`\`\`

### Interface Extends Over Intersection
\`\`\`tsx
// BAD — intersection types are expensive to compute
type Extended = BaseType & { extra: string } & { more: number };

// GOOD — interface extends is cached by the compiler
interface Extended extends BaseType {
  extra: string;
  more: number;
}
\`\`\`

### Rules
- **Avoid recursive conditional types** deeper than 3 levels — use iterative mapped types instead
- **Minimize computed types** in hot paths (function parameters, return types used in many places)
- **Use \`interface\` for object shapes**, \`type\` for unions, intersections, and mapped types
- **Annotate complex return types** explicitly — don't force the compiler to infer through 5 layers
- **Avoid generic defaults that trigger deep inference** — provide explicit type arguments at call sites
- **Break circular type references** — extract shared shapes into separate interfaces

## Compiler Configuration

### Strict Mode (all projects)
\`\`\`jsonc
{
  "compilerOptions": {
    "strict": true,                    // Enables ALL strict checks
    "noUncheckedIndexedAccess": true,  // arr[0] is T | undefined
    "exactOptionalProperties": true,   // undefined ≠ missing
    "noFallthroughCasesInSwitch": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,           // Required for most bundlers
    "verbatimModuleSyntax": true       // Explicit import/export type
  }
}
\`\`\`

### Build Performance
\`\`\`jsonc
{
  "compilerOptions": {
    "incremental": true,               // Cache type-check results
    "tsBuildInfoFile": ".tsbuildinfo",
    "skipLibCheck": true               // Skip .d.ts checking (safe for apps)
  }
}
\`\`\`

### Project References (monorepos)
\`\`\`jsonc
// tsconfig.json (root)
{
  "references": [
    { "path": "packages/core" },
    { "path": "packages/server" },
    { "path": "packages/cli" }
  ]
}

// packages/core/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true
  }
}
\`\`\`

### TypeScript 6.0+ Features
- **\`#/\` subpath imports**: \`import { utils } from "#/lib/utils"\` — no more \`../../../\` relative paths. Configure in \`package.json\` \`"imports"\` field.
- **\`es2025\` target**: Set, Iterator, Promise.withResolvers, RegExp v flag
- **\`--noCheck\`**: Skip type-checking in CI (when pre-checked) for faster builds
- **\`--stableTypeOrdering\`**: Deterministic declaration output for reproducible builds
- **\`isolatedDeclarations\`**: Generate \`.d.ts\` without type-checking — enables parallel builds

## Advanced Types

### Constrained Generics
\`\`\`tsx
// Constrain to ensure property exists
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Constrain with interface
function merge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {
  return { ...target, ...source };
}
\`\`\`

### Conditional Types
\`\`\`tsx
// Extract return type from async function
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

// Distributive conditional
type NonNullableDeep<T> = T extends null | undefined ? never : T extends object ? { [K in keyof T]: NonNullableDeep<T[K]> } : T;

// Infer from function
type Parameters<T> = T extends (...args: infer P) => unknown ? P : never;
\`\`\`

### Mapped Types
\`\`\`tsx
// Make all properties optional recursively
type DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P] };

// Remove readonly
type Mutable<T> = { -readonly [P in keyof T]: T[P] };

// Key remapping
type Getters<T> = { [K in keyof T as \`get\${Capitalize<string & K>}\`]: () => T[K] };
\`\`\`

### Template Literal Types
\`\`\`tsx
// Event name typing
type EventName<T extends string> = \`on\${Capitalize<T>}\`;
type Events = EventName<"click" | "focus" | "blur">; // "onClick" | "onFocus" | "onBlur"

// Route parameter extraction
type ExtractParams<T extends string> =
  T extends \`\${string}:\${infer Param}/\${infer Rest}\`
    ? Param | ExtractParams<Rest>
    : T extends \`\${string}:\${infer Param}\`
      ? Param
      : never;
type Params = ExtractParams<"/users/:id/posts/:postId">; // "id" | "postId"
\`\`\`

### Utility Type Patterns
\`\`\`tsx
// Deep readonly
type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P] };

// Make specific keys required
type RequireKeys<T, K extends keyof T> = T & Required<Pick<T, K>>;

// Object paths as union
type Paths<T, D extends number = 3> = [D] extends [never]
  ? never
  : T extends object
    ? { [K in keyof T]-?: K extends string ? \`\${K}\` | \`\${K}.\${Paths<T[K]>}\` : never }[keyof T]
    : never;
\`\`\`

## Type Safety Patterns

### Branded Types
\`\`\`tsx
// Prevent mixing IDs of different entities
type UserId = string & { readonly __brand: "UserId" };
type OrderId = string & { readonly __brand: "OrderId" };

function createUserId(id: string): UserId { return id as UserId; }
function createOrderId(id: string): OrderId { return id as OrderId; }

function getUser(id: UserId) { /* ... */ }
getUser(createOrderId("123")); // TS Error! OrderId is not UserId
\`\`\`

### Discriminated Unions with Exhaustive Matching
\`\`\`tsx
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; width: number; height: number }
  | { kind: "triangle"; base: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle": return Math.PI * shape.radius ** 2;
    case "rect": return shape.width * shape.height;
    case "triangle": return 0.5 * shape.base * shape.height;
    default: {
      const _exhaustive: never = shape;  // Compile error if case missed
      return _exhaustive;
    }
  }
}
\`\`\`

### Result Pattern
\`\`\`tsx
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };

function ok<T>(value: T): Result<T, never> { return { ok: true, value }; }
function err<E>(error: E): Result<never, E> { return { ok: false, error }; }

async function parseConfig(path: string): Promise<Result<Config, ParseError>> {
  try {
    const raw = await readFile(path, "utf-8");
    return ok(JSON.parse(raw));
  } catch (e) {
    return err(new ParseError(\`Failed to parse \${path}\`, { cause: e }));
  }
}

// Usage — forces error handling
const result = await parseConfig("config.json");
if (!result.ok) {
  console.error(result.error.message);
  process.exit(1);
}
const config = result.value;  // Type-narrowed to Config
\`\`\`

## Async Patterns

### Parallel Execution
\`\`\`tsx
// Promise.all — fail-fast on first rejection
const [users, posts] = await Promise.all([getUsers(), getPosts()]);

// Promise.allSettled — get all results regardless of failures
const results = await Promise.allSettled([getUsers(), getPosts(), getComments()]);
for (const r of results) {
  if (r.status === "fulfilled") process(r.value);
  else logError(r.reason);
}
\`\`\`

### AbortController
\`\`\`tsx
async function fetchWithTimeout(url: string, timeoutMs: number): Promise<Response> {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
  try {
    return await fetch(url, { signal: controller.signal });
  } finally {
    clearTimeout(timeout);
  }
}
\`\`\`

### Async Iterators
\`\`\`tsx
async function* paginate<T>(fetcher: (page: number) => Promise<T[]>): AsyncGenerator<T> {
  let page = 0;
  while (true) {
    const items = await fetcher(page++);
    if (items.length === 0) break;
    yield* items;
  }
}

// Usage
for await (const user of paginate(fetchUsersPage)) {
  processUser(user);
}
\`\`\`

## Module Organization

### Barrel File Performance
\`\`\`tsx
// BAD — barrel files cause entire module tree to load
// index.ts
export * from "./userService";
export * from "./orderService";
export * from "./paymentService";

// GOOD — direct imports skip barrel overhead
import { UserService } from "./services/userService";
\`\`\`

### Type-Only Imports
\`\`\`tsx
// Always use type-only imports for types
import type { User, CreateUserDto } from "./types";
import { UserService } from "./userService";
// With verbatimModuleSyntax, this is enforced
\`\`\`

### Re-export Patterns
\`\`\`tsx
// Public API surface — explicit re-exports
export { UserService } from "./userService";
export type { User, CreateUserDto } from "./types";
// Don't export internal implementation details
\`\`\`

## Memory & Runtime

### WeakRef for Caches
\`\`\`tsx
class WeakCache<K extends object, V> {
  private cache = new Map<K, WeakRef<V & object>>();
  private registry = new FinalizationRegistry<K>(key => this.cache.delete(key));

  set(key: K, value: V & object): void {
    this.cache.set(key, new WeakRef(value));
    this.registry.register(value, key);
  }

  get(key: K): V | undefined {
    return this.cache.get(key)?.deref();
  }
}
\`\`\`

### Efficient Data Structures
\`\`\`tsx
// Use Map/Set for frequent lookups
const userIndex = new Map<string, User>();       // O(1) lookup
const activeIds = new Set<string>();              // O(1) has/add/delete

// NOT plain objects for dynamic keys
const userIndex: Record<string, User> = {};      // Slower for frequent mutations
\`\`\`

### Runtime Rules
- Minimize \`Reflect.metadata\` and decorator reflection — adds runtime overhead
- Prefer \`structuredClone()\` over \`JSON.parse(JSON.stringify())\` for deep cloning
- Use \`Object.freeze()\` for truly immutable constants
- Avoid \`eval()\`, \`new Function()\`, and dynamic \`require()\` — security + performance issues

## Modern JavaScript Patterns

### Nullish Handling
\`\`\`tsx
const port = config.port ?? 3000;          // Only for null/undefined
const name = user?.profile?.displayName;   // Optional chaining
const normalized = (input ??= defaultValue); // Nullish assignment
\`\`\`

### Immutable Updates
\`\`\`tsx
// Object spread for shallow updates
const updated = { ...user, name: "New Name" };

// structuredClone for deep copy
const deep = structuredClone(complexObject);

// Array immutable operations
const added = [...items, newItem];
const removed = items.filter(i => i.id !== targetId);
const updated = items.map(i => i.id === targetId ? { ...i, ...changes } : i);
\`\`\`

### Pipe Pattern
\`\`\`tsx
function pipe<T>(value: T, ...fns: Array<(v: unknown) => unknown>): unknown {
  return fns.reduce((acc, fn) => fn(acc), value as unknown);
}

// Usage
const result = pipe(
  rawData,
  validate,
  normalize,
  transform,
  serialize
);
\`\`\`

## Decision Flow

When writing TypeScript:

1. **Interface or Type?** → Object shape = interface. Union/intersection/mapped = type.
2. **Generic needed?** → If the function works with multiple types and you need to preserve the type → yes. Otherwise keep it simple.
3. **Strict enough?** → Enable all strict flags. Use branded types for domain IDs. Use discriminated unions for variants.
4. **Performance?** → Check: Are there deep conditional types? Circular references? Massive unions? Simplify if so.
5. **Import style?** → \`import type\` for types. Direct imports, not barrel files. Named exports, not default.
6. **Error handling?** → Result pattern for expected errors. throw for unexpected/programmer errors.
7. **Async?** → Promise.all for parallel. AbortController for timeouts. AsyncGenerator for streams.
`}];export{e as default};