TypeScript Best Practices
Production-grade TypeScript development with schema-first design, strict type safety, and immutable patterns.
Core Principles
- Type Safety at All Boundaries - Runtime validation (schemas) + compile-time safety (TypeScript)
- Schema-First Development - Define schemas before types, derive types from schemas
- Immutability - No data mutation, always create new values
- Explicit Types - No implicit any, strict mode enabled
- Behavior over implementation - Focus on contracts and outcomes
Quick Reference
| Topic |
Guide |
| Schema-first development, when to use schemas vs types, test factories |
schemas.md |
| Type vs interface, any vs unknown, assertions, strict mode |
types-interfaces.md |
| Immutability patterns, readonly, forbidden methods, error handling |
immutability.md |
| Branded types, utility types, code smells reference |
utilities.md |
| Common TypeScript patterns with examples |
patterns.md |
When to Use Each Guide
Schemas
Use schemas.md when you need:
- Schema-first development patterns
- Decision framework: when schema is required vs optional
- Trust boundary identification
- Test data factory patterns with schema validation
- Examples of schema usage (API responses, business validation)
Types and Interfaces
Use types-interfaces.md when you need:
- Type vs interface guidance
- The any vs unknown decision
- Type assertion best practices
- Strict mode configuration
- tsconfig.json settings
Immutability
Use immutability.md when you need:
- Immutability patterns (spread operators)
- Readonly modifiers
- Forbidden array methods reference
- Options objects vs positional parameters
- Boolean parameter anti-patterns
- Result types for error handling
- Early return patterns
Utilities
Use utilities.md when you need:
- Branded types for domain concepts
- Built-in utility types (Pick, Omit, Partial, etc.)
- Custom utility types
- Code smell reference tables
Patterns
Use patterns.md when you need:
- Schema-first examples at trust boundaries
- Internal type examples without schemas
- Schema with test factory patterns
- Result type for error handling
- Branded types for domain safety
- Immutable array operations
- Options object pattern
Quick Reference: Decision Trees
Should I use a schema?
Does data come from outside the application?
├── Yes → Schema required
└── No → Does it have validation rules (format, range, enum)?
├── Yes → Schema required
└── No → Is it shared between systems?
├── Yes → Schema required
└── No → Type is fine
Should I use type or interface?
Am I defining a behavior contract for dependency injection?
├── Yes → interface
└── No → type
Should I use any or unknown?
Never use any.
Always use unknown for truly unknown types.
Options object or positional parameters?
How many parameters?
├── 1-2 → Positional is fine
└── 3+ → Use options object
Summary Checklist
Before committing TypeScript code, verify:
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: typescript-103description: WHEN writing TypeScript, defining types/schemas, or building type-safe apps; outputs strict, schema-first, production-ready code. Use when this capability is needed.4---56# TypeScript Best Practices78Production-grade TypeScript development with schema-first design, strict type safety, and immutable patterns.910## Core Principles11121. **Type Safety at All Boundaries** - Runtime validation (schemas) + compile-time safety (TypeScript)132. **Schema-First Development** - Define schemas before types, derive types from schemas143. **Immutability** - No data mutation, always create new values154. **Explicit Types** - No implicit any, strict mode enabled165. **Behavior over implementation** - Focus on contracts and outcomes1718## Quick Reference1920| Topic | Guide |21| ---------------------------------------------------------------------- | ----------------------------------------------------- |22| Schema-first development, when to use schemas vs types, test factories | [schemas.md](references/schemas.md) |23| Type vs interface, any vs unknown, assertions, strict mode | [types-interfaces.md](references/types-interfaces.md) |24| Immutability patterns, readonly, forbidden methods, error handling | [immutability.md](references/immutability.md) |25| Branded types, utility types, code smells reference | [utilities.md](references/utilities.md) |26| Common TypeScript patterns with examples | [patterns.md](references/patterns.md) |2728## When to Use Each Guide2930### Schemas3132Use [schemas.md](references/schemas.md) when you need:3334- Schema-first development patterns35- Decision framework: when schema is required vs optional36- Trust boundary identification37- Test data factory patterns with schema validation38- Examples of schema usage (API responses, business validation)3940### Types and Interfaces4142Use [types-interfaces.md](references/types-interfaces.md) when you need:4344- Type vs interface guidance45- The any vs unknown decision46- Type assertion best practices47- Strict mode configuration48- tsconfig.json settings4950### Immutability5152Use [immutability.md](references/immutability.md) when you need:5354- Immutability patterns (spread operators)55- Readonly modifiers56- Forbidden array methods reference57- Options objects vs positional parameters58- Boolean parameter anti-patterns59- Result types for error handling60- Early return patterns6162### Utilities6364Use [utilities.md](references/utilities.md) when you need:6566- Branded types for domain concepts67- Built-in utility types (Pick, Omit, Partial, etc.)68- Custom utility types69- Code smell reference tables7071### Patterns7273Use [patterns.md](references/patterns.md) when you need:7475- Schema-first examples at trust boundaries76- Internal type examples without schemas77- Schema with test factory patterns78- Result type for error handling79- Branded types for domain safety80- Immutable array operations81- Options object pattern8283## Quick Reference: Decision Trees8485### Should I use a schema?8687```88Does data come from outside the application?89├── Yes → Schema required90└── No → Does it have validation rules (format, range, enum)?91 ├── Yes → Schema required92 └── No → Is it shared between systems?93 ├── Yes → Schema required94 └── No → Type is fine95```9697### Should I use `type` or `interface`?9899```100Am I defining a behavior contract for dependency injection?101├── Yes → interface102└── No → type103```104105### Should I use `any` or `unknown`?106107```108Never use any.109Always use unknown for truly unknown types.110```111112### Options object or positional parameters?113114```115How many parameters?116├── 1-2 → Positional is fine117└── 3+ → Use options object118```119120## Summary Checklist121122Before committing TypeScript code, verify:123124- [ ] Strict mode enabled in tsconfig.json125- [ ] No `any` types (use `unknown` instead)126- [ ] Schemas at all trust boundaries (API, user input, files)127- [ ] Types derived from schemas using `z.infer`128- [ ] Using `type` for data, `interface` only for behavior contracts129- [ ] All data structures use `readonly` where appropriate130- [ ] No array mutations (push, pop, splice, etc.)131- [ ] Functions with 3+ params use options objects132- [ ] No boolean positional parameters133- [ ] Result types for operations that can fail134- [ ] Early returns instead of nested conditionals135- [ ] Test factories validate with schemas136- [ ] Branded types for domain concepts that shouldn't mix137- [ ] Explicit return types on functions138139---140> Converted and distributed by [TomeVault](https://tomevault.io/claim/mintuz) — claim your Tome and manage your conversions.141<!-- tomevault:4.0:skill_md:2026-04-11 -->