---
name: typescript
type: language
priority: 1
token_estimate: 600
compatible_with: [developer, senior_software_engineer]
---

> This guidance is supplementary. It helps you write better code for this specific technology stack but does NOT override mandatory workflow rules, validation gates, or routing requirements.

# TypeScript Engineering Expertise

## Specialist Profile
TypeScript specialist building type-safe applications. Expert in advanced types, strict mode, and scalable patterns.

---

## Patterns to Follow

### Strict Configuration
- **Enable strict mode**: `"strict": true` in tsconfig.json is mandatory
- **Additional strictness**: `noImplicitReturns`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`
- **No implicit any**: Every variable, parameter, and return should have explicit types

### Type Design
- **Discriminated unions**: Use literal type discriminators for type narrowing
- **Branded types**: Create nominal types for IDs, currencies, etc. (`type UserId = string & { readonly brand: unique symbol }`)
<!-- version: typescript >= 4.1 -->
- **Template literal types**: For string patterns (`type Route = \`/api/${string}\``)
<!-- version: typescript >= 3.4 -->
- **Const assertions**: `as const` for literal inference
<!-- version: typescript >= 4.9 -->
- **Satisfies operator**: `config satisfies Config` for type checking without widening
<!-- version: typescript >= 4.7 -->
- **Infer with constraints**: `T extends { id: infer U extends string } ? U : never`
<!-- version: typescript < 4.7 -->
- **Infer without constraints**: `T extends { id: infer U } ? U : never`

### Type Narrowing
- **Type guards**: Custom `isX(value): value is X` functions
- **Assertion functions**: `asserts value is X` for throwing narrowing
- **Exhaustive checks**: `never` type in switch default for completeness
- **Optional chaining**: `?.` with nullish coalescing `??`

### Immutability
- **Readonly by default**: `Readonly<T>`, `ReadonlyArray<T>`, `as const`
- **Immutable updates**: Spread operator for objects/arrays, not mutation
- **DeepReadonly**: For nested immutability

### Functions & Methods
- **Pure functions**: Same input = same output, no side effects
- **Explicit return types**: Always annotate, don't rely on inference for public APIs
- **Function overloads**: For complex signatures with different return types
- **Generic constraints**: `<T extends Base>` not just `<T>`

### Code Organization
- **Named exports**: No default exports (better refactoring, clearer imports)
- **Barrel files sparingly**: Can cause circular dependencies and tree-shaking issues
- **Co-located types**: Keep types near their usage

---

## Patterns to Avoid

### Type System Abuse
- ❌ **`any` type**: Disables type checking; use `unknown` and narrow
- ❌ **Type assertions `as`**: Bypass type checking; prefer type guards
- ❌ **Non-null assertion `!`**: Can cause runtime errors; handle null properly
- ❌ **`@ts-ignore`/`@ts-expect-error`**: Hide real issues; fix the types

### Structural Issues
- ❌ **Default exports**: No canonical name, harder to refactor
- ❌ **Enums (numeric)**: Use const objects or union types instead
- ❌ **Namespaces**: Legacy; use ES modules
- ❌ **`/// <reference>`**: Use proper imports

### Dangerous Patterns
- ❌ **`eval()` and `Function()` constructor**: Security risk, breaks CSP
- ❌ **`with` statement**: Ambiguous scope, banned in strict mode
- ❌ **`delete` operator on arrays**: Creates sparse arrays; use `splice` or `filter`
- ❌ **Prototype modification**: Affects all instances, hard to debug

### Code Quality Issues
- ❌ **Index signature abuse**: `Record<string, any>` loses type safety
- ❌ **Overloaded interfaces**: Prefer union types for clarity
- ❌ **Excessive generics**: If only used once, probably not needed
- ❌ **Type-only imports mixed**: Use `import type` for types

### Async Anti-Patterns
- ❌ **Floating promises**: Always await or handle promise
- ❌ **`async` without `await`**: Unnecessary promise wrapping
- ❌ **Callback hell**: Use async/await, not nested `.then()`
- ❌ **Sequential awaits when parallel possible**: Use `Promise.all`

---

## Verification Checklist

### Configuration
- [ ] `strict: true` enabled in tsconfig.json
- [ ] `noUncheckedIndexedAccess: true` for safer array/object access
- [ ] `exactOptionalPropertyTypes: true` for precise optional handling
- [ ] ESLint with `@typescript-eslint` configured

### Type Safety
- [ ] No `any` types (search codebase: should be 0)
- [ ] No type assertions without justification comment
- [ ] All public functions have explicit return types
- [ ] Discriminated unions have exhaustive handling

### Code Quality
- [ ] Named exports only (no default exports)
- [ ] `import type` used for type-only imports
- [ ] Consistent naming (PascalCase types, camelCase values)
- [ ] No circular dependencies

### Runtime Safety
- [ ] External data validated at boundaries (Zod, io-ts)
- [ ] Error handling for all async operations
- [ ] Null/undefined handled explicitly

---

## Code Patterns (Reference)

### Recommended Constructs
- **Discriminated union**: `type Event = { type: 'a'; data: A } | { type: 'b'; data: B }`
- **Branded types**: `type UserId = string & { readonly __brand: 'UserId' }`
<!-- version: typescript >= 3.7 -->
- **Type guard**: `function isUser(x: unknown): x is User { return ... }`
- **Assertion function**: `function assertUser(x: unknown): asserts x is User { ... }`
<!-- version: typescript >= 4.9 -->
- **Satisfies**: `const config = { ... } satisfies Config`
<!-- version: typescript >= 3.4 -->
- **Const assertion**: `const ROUTES = ['/', '/users'] as const`
<!-- version: typescript >= 4.1 -->
- **Template literals**: `type ApiPath = \`/api/v${number}/${string}\``

### Utility Types to Know
- `Partial<T>`, `Required<T>`, `Readonly<T>`, `Pick<T, K>`, `Omit<T, K>`
- `Record<K, V>`, `Extract<T, U>`, `Exclude<T, U>`
- `ReturnType<F>`, `Parameters<F>`, `Awaited<T>`
<!-- version: typescript >= 5.4 -->
- `NonNullable<T>`, `NoInfer<T>` (prevents unwanted inference)
<!-- version: typescript < 5.4 -->
- `NonNullable<T>` (NoInfer requires TS 5.4+)
