TypeScript — Unified Skill
TypeScript 5.x language fundamentals, developer workflow, TDD discipline, and architecture patterns for building safe, maintainable applications.
Fundamentals
Compiler Configuration
Enable strict: true plus additional safety flags (noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitOverride, noPropertyAccessFromIndexSignature). Use path aliases (@src/*, @test/*, @lib/*) — never use ../../ imports beyond one level deep.
Type System
- Prefer union types over enums — simpler, tree-shakeable
- Prefer interfaces for public API shapes; type aliases for unions, intersections, mapped/conditional types
- Generics: constrain with
extends, use defaults, keep type parameters minimal
- Utility types:
Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, ReturnType, Awaited
- Discriminated unions: tag with a literal discriminant, use
assertNever for exhaustiveness
- Branded types: prevent mixing structurally identical types with smart constructors
- Mapped types:
Nullable<T>, DeepReadonly<T>, key remapping with template literals
- Conditional types:
infer, distributive conditionals
Functional Patterns
- ADTs: sum types (discriminated unions) and product types (objects, tuples)
- Boolean elimination: replace boolean flags with explicit state variants
- Option<T>: explicit nullable values with
_tag: "None" | "Some"
- Result<T, E>: explicit error handling with
_tag: "Ok" | "Err"
Anti-Patterns (never do)
any without justification — use unknown and narrow
! non-null assertion on uncertain values — use ?? or guard
@ts-ignore — use @ts-expect-error with explanation if truly needed
{} as Type — validate at boundaries with Zod or guards
- String enums — use union types
- Deep relative imports — use path aliases
For details, see refs/fundamentals.md.
Developer Workflow
First Principles
- Write the failing test first — no implementation without a red test
- Strict types, zero
any — every any is a bug waiting to happen
- Behaviour, not implementation — tests prove what, not how
- Self-verify before declaring done — run the full quality suite
- Small commits, conventional messages — one logical change per commit
TDD Cycle
RED Write a failing test → confirm it fails with the right reason
GREEN Write minimum code to pass → confirm green
REFACTOR Remove duplication, improve names → confirm still green
COMMIT Conventional commit message
Toolchain Run Order
npx tsc --noEmit # Type check
npx eslint src/ tests/ --fix # Lint
npx prettier --write src/ tests/ # Format
npx vitest run --coverage # Tests + coverage
Two Modes
| Input |
Mode |
Reference |
| Spec (TRD, ADR, design doc) |
Implementation |
refs/workflow-implementation.md |
| Rejection feedback |
Remediation |
refs/workflow-remediation.md |
Dependency Injection in Tests
Use in-memory fakes that implement the interface — no vi.mock() for DI. vi.fn() only for callbacks, timers, and spying without replacing behaviour.
For details, see refs/developer-workflow.md.
TDD Discipline
The Three Laws
- Do not write production code unless it is to make a failing test pass
- Do not write more of a test than is sufficient to fail
- Do not write more production code than is sufficient to pass the current test
Test Pyramid
~70% unit (pure logic, no I/O), ~20% integration (real DB/HTTP), ~10% E2E (critical journeys).
Key Patterns
- Fakes over mocks: real simplified implementations, compile-checked against the interface
- Parametrised tests:
it.each(...) for input/output matrices
- Async tests:
rejects.toThrow(), fake timers with vi.useFakeTimers()
- Test fixtures: builder functions (
makeUser(overrides)) with @faker-js/faker
- Integration tests: testcontainers for real DB
- Test naming:
GIVEN <precondition> WHEN <action> THEN <expected>
Coverage Gates
| Metric |
Threshold |
| Lines, Functions, Branches, Statements |
>= 80% |
For details, see refs/tdd.md.
Architecture
Layered Design
domain/ Pure business logic — no framework imports
application/ Use-cases, commands, queries, ports (interfaces)
infrastructure/ Adapters: DB, HTTP clients, messaging
interface/ Delivery: REST, CLI, GraphQL, workers
shared/ Cross-cutting: logger, config, result type
Dependency rule: inner layers never import from outer layers.
Key Patterns
- Interface-first design: define ports in
application/ports/, implement in infrastructure/
- Composition root: assemble the full dependency graph in
bootstrap.ts — never new in domain/application
- Configuration: Zod schema validation at startup, fail-fast on missing env vars
- Error hierarchy:
DomainError base with NotFoundError, ConflictError, ValidationError
- HTTP error mapping: interface layer only, RFC 9457 Problem Details
- Module boundaries: each module exposes via
index.ts; no reaching into internals
12-Factor (TypeScript Edition)
Config via env vars, stateless processes, backing services injected via interfaces, structured JSON logs to stdout, graceful shutdown.
Observability
Every use-case gets an OTel span. Structured logging only (pino). Metrics naming: <service>.<entity>.<operation>.
Technology Stack Defaults
| Concern |
Default |
| Runtime |
Node.js 22 LTS |
| Packages |
pnpm 9 |
| HTTP |
Fastify |
| Validation |
Zod |
| ORM |
Drizzle |
| Testing |
Vitest |
| Lint + Format |
ESLint 9 flat + Prettier |
| Observability |
OpenTelemetry SDK |
For details, see refs/architecture.md.
Quality Gates
Before Every Commit
npx tsc --noEmit && npx eslint src/ tests/ --fix && npx prettier --write src/ tests/ && npx vitest run --coverage
PR Checklist
Design Checklist (architecture changes)
Reference Files
| File |
Purpose |
refs/fundamentals.md |
Full type system, generics, utility types, modules, functional patterns |
refs/developer-workflow.md |
TDD workflow, Vitest config, ESLint config, DI patterns, code style |
refs/tdd.md |
Red-Green-Refactor, fakes over mocks, parametrised tests, async, fixtures |
refs/architecture.md |
Clean architecture, DI, module boundaries, error strategy, observability |
refs/adts.md |
Algebraic data types — nested ADTs, generic sum types, testing |
refs/branded-types.md |
Brand composition, NonEmptyArray, JSON serialisation, smart constructors |
refs/functional-migration.md |
Incremental adoption playbook, strict mode, CI enforcement |
refs/option-result.md |
Chaining, error accumulation, HTTP handling, conversion helpers |
refs/code-patterns.md |
Subprocess execution, resource cleanup, Zod config, typed errors |
refs/test-patterns.md |
Debuggability-first 4-part test progression |
refs/verification-checklist.md |
Full pre-submission checklist with tool commands |
refs/workflow-implementation.md |
Phase-by-phase implementation protocol (TDD) |
refs/workflow-remediation.md |
Phase-by-phase remediation protocol (fixes) |
refs/REFERENCES.md |
External links — language, toolchain, testing, architecture |
Scripts
| Script |
Purpose |
scripts/check.sh |
Core TypeScript quality checks |
scripts/dev_check.sh |
Developer workflow quality checks |
scripts/tdd_check.sh |
TDD quality checks |
scripts/arch_check.sh |
Architecture quality checks |
Templates
| Template |
Purpose |
templates/tsconfig.json |
Strict baseline tsconfig |
templates/types_example.ts |
Type system examples |
templates/eslint.config.js |
ESLint 9 flat config |
templates/test_example.ts |
Vitest test examples |
templates/vitest.config.ts |
Vitest configuration |
templates/di_container.ts |
DI composition root example |
templates/result_type.ts |
Result type implementation |
Source: mwigge/agent-toolkit-bundle — distributed by TomeVault.
1---2name: typescript-243description: Comprehensive TypeScript skill — language fundamentals, type system, generics, developer workflow (TDD, Vitest, DI), Red-Green-Refactor discipline, and clean architecture patterns. Use for any TypeScript development, testing, or design task. Use when this capability is needed.4---56# TypeScript — Unified Skill78TypeScript 5.x language fundamentals, developer workflow, TDD discipline, and architecture patterns for building safe, maintainable applications.910---1112## Fundamentals1314### Compiler Configuration1516Enable `strict: true` plus additional safety flags (`noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, `noPropertyAccessFromIndexSignature`). Use path aliases (`@src/*`, `@test/*`, `@lib/*`) — never use `../../` imports beyond one level deep.1718### Type System1920- **Prefer union types** over enums — simpler, tree-shakeable21- **Prefer interfaces** for public API shapes; **type aliases** for unions, intersections, mapped/conditional types22- **Generics**: constrain with `extends`, use defaults, keep type parameters minimal23- **Utility types**: `Partial`, `Required`, `Readonly`, `Pick`, `Omit`, `Record`, `Exclude`, `Extract`, `NonNullable`, `ReturnType`, `Awaited`24- **Discriminated unions**: tag with a literal discriminant, use `assertNever` for exhaustiveness25- **Branded types**: prevent mixing structurally identical types with smart constructors26- **Mapped types**: `Nullable<T>`, `DeepReadonly<T>`, key remapping with template literals27- **Conditional types**: `infer`, distributive conditionals2829### Functional Patterns3031- **ADTs**: sum types (discriminated unions) and product types (objects, tuples)32- **Boolean elimination**: replace boolean flags with explicit state variants33- **Option\<T\>**: explicit nullable values with `_tag: "None" | "Some"`34- **Result\<T, E\>**: explicit error handling with `_tag: "Ok" | "Err"`3536### Anti-Patterns (never do)3738- `any` without justification — use `unknown` and narrow39- `!` non-null assertion on uncertain values — use `??` or guard40- `@ts-ignore` — use `@ts-expect-error` with explanation if truly needed41- `{} as Type` — validate at boundaries with Zod or guards42- String enums — use union types43- Deep relative imports — use path aliases4445For details, see [`refs/fundamentals.md`](./refs/fundamentals.md).4647---4849## Developer Workflow5051### First Principles52531. Write the failing test first — no implementation without a red test542. Strict types, zero `any` — every `any` is a bug waiting to happen553. Behaviour, not implementation — tests prove what, not how564. Self-verify before declaring done — run the full quality suite575. Small commits, conventional messages — one logical change per commit5859### TDD Cycle6061```62RED Write a failing test → confirm it fails with the right reason63GREEN Write minimum code to pass → confirm green64REFACTOR Remove duplication, improve names → confirm still green65COMMIT Conventional commit message66```6768### Toolchain Run Order6970```bash71npx tsc --noEmit # Type check72npx eslint src/ tests/ --fix # Lint73npx prettier --write src/ tests/ # Format74npx vitest run --coverage # Tests + coverage75```7677### Two Modes7879| Input | Mode | Reference |80|-------|------|-----------|81| Spec (TRD, ADR, design doc) | Implementation | `refs/workflow-implementation.md` |82| Rejection feedback | Remediation | `refs/workflow-remediation.md` |8384### Dependency Injection in Tests8586Use in-memory fakes that implement the interface — no `vi.mock()` for DI. `vi.fn()` only for callbacks, timers, and spying without replacing behaviour.8788For details, see [`refs/developer-workflow.md`](./refs/developer-workflow.md).8990---9192## TDD Discipline9394### The Three Laws95961. Do not write production code unless it is to make a failing test pass972. Do not write more of a test than is sufficient to fail983. Do not write more production code than is sufficient to pass the current test99100### Test Pyramid101102~70% unit (pure logic, no I/O), ~20% integration (real DB/HTTP), ~10% E2E (critical journeys).103104### Key Patterns105106- **Fakes over mocks**: real simplified implementations, compile-checked against the interface107- **Parametrised tests**: `it.each(...)` for input/output matrices108- **Async tests**: `rejects.toThrow()`, fake timers with `vi.useFakeTimers()`109- **Test fixtures**: builder functions (`makeUser(overrides)`) with `@faker-js/faker`110- **Integration tests**: testcontainers for real DB111- **Test naming**: `GIVEN <precondition> WHEN <action> THEN <expected>`112113### Coverage Gates114115| Metric | Threshold |116|--------|-----------|117| Lines, Functions, Branches, Statements | >= 80% |118119For details, see [`refs/tdd.md`](./refs/tdd.md).120121---122123## Architecture124125### Layered Design126127```128domain/ Pure business logic — no framework imports129application/ Use-cases, commands, queries, ports (interfaces)130infrastructure/ Adapters: DB, HTTP clients, messaging131interface/ Delivery: REST, CLI, GraphQL, workers132shared/ Cross-cutting: logger, config, result type133```134135**Dependency rule**: inner layers never import from outer layers.136137### Key Patterns138139- **Interface-first design**: define ports in `application/ports/`, implement in `infrastructure/`140- **Composition root**: assemble the full dependency graph in `bootstrap.ts` — never `new` in domain/application141- **Configuration**: Zod schema validation at startup, fail-fast on missing env vars142- **Error hierarchy**: `DomainError` base with `NotFoundError`, `ConflictError`, `ValidationError`143- **HTTP error mapping**: interface layer only, RFC 9457 Problem Details144- **Module boundaries**: each module exposes via `index.ts`; no reaching into internals145146### 12-Factor (TypeScript Edition)147148Config via env vars, stateless processes, backing services injected via interfaces, structured JSON logs to stdout, graceful shutdown.149150### Observability151152Every use-case gets an OTel span. Structured logging only (pino). Metrics naming: `<service>.<entity>.<operation>`.153154### Technology Stack Defaults155156| Concern | Default |157|---------|---------|158| Runtime | Node.js 22 LTS |159| Packages | pnpm 9 |160| HTTP | Fastify |161| Validation | Zod |162| ORM | Drizzle |163| Testing | Vitest |164| Lint + Format | ESLint 9 flat + Prettier |165| Observability | OpenTelemetry SDK |166167For details, see [`refs/architecture.md`](./refs/architecture.md).168169---170171## Quality Gates172173### Before Every Commit174175```bash176npx tsc --noEmit && npx eslint src/ tests/ --fix && npx prettier --write src/ tests/ && npx vitest run --coverage177```178179### PR Checklist180181- [ ] All functions have explicit return type annotations182- [ ] All public functions have JSDoc183- [ ] Tests prove behaviour, not implementation184- [ ] No `any`, no `!`, no `@ts-ignore`185- [ ] No hardcoded secrets186- [ ] No deep relative imports187- [ ] Coverage >= 80% on new code188- [ ] Conventional commit message189190### Design Checklist (architecture changes)191192- [ ] Module boundaries defined — public vs internal193- [ ] Dependencies flow inward194- [ ] All external deps injected via interfaces195- [ ] Config validated at startup with fail-fast196- [ ] Error hierarchy documented197- [ ] OTel spans on every use-case198- [ ] Parameterised queries for every DB call199- [ ] Input validated at boundary (Zod)200- [ ] Graceful shutdown handler registered201202---203204## Reference Files205206| File | Purpose |207|------|---------|208| `refs/fundamentals.md` | Full type system, generics, utility types, modules, functional patterns |209| `refs/developer-workflow.md` | TDD workflow, Vitest config, ESLint config, DI patterns, code style |210| `refs/tdd.md` | Red-Green-Refactor, fakes over mocks, parametrised tests, async, fixtures |211| `refs/architecture.md` | Clean architecture, DI, module boundaries, error strategy, observability |212| `refs/adts.md` | Algebraic data types — nested ADTs, generic sum types, testing |213| `refs/branded-types.md` | Brand composition, NonEmptyArray, JSON serialisation, smart constructors |214| `refs/functional-migration.md` | Incremental adoption playbook, strict mode, CI enforcement |215| `refs/option-result.md` | Chaining, error accumulation, HTTP handling, conversion helpers |216| `refs/code-patterns.md` | Subprocess execution, resource cleanup, Zod config, typed errors |217| `refs/test-patterns.md` | Debuggability-first 4-part test progression |218| `refs/verification-checklist.md` | Full pre-submission checklist with tool commands |219| `refs/workflow-implementation.md` | Phase-by-phase implementation protocol (TDD) |220| `refs/workflow-remediation.md` | Phase-by-phase remediation protocol (fixes) |221| `refs/REFERENCES.md` | External links — language, toolchain, testing, architecture |222223## Scripts224225| Script | Purpose |226|--------|---------|227| `scripts/check.sh` | Core TypeScript quality checks |228| `scripts/dev_check.sh` | Developer workflow quality checks |229| `scripts/tdd_check.sh` | TDD quality checks |230| `scripts/arch_check.sh` | Architecture quality checks |231232## Templates233234| Template | Purpose |235|----------|---------|236| `templates/tsconfig.json` | Strict baseline tsconfig |237| `templates/types_example.ts` | Type system examples |238| `templates/eslint.config.js` | ESLint 9 flat config |239| `templates/test_example.ts` | Vitest test examples |240| `templates/vitest.config.ts` | Vitest configuration |241| `templates/di_container.ts` | DI composition root example |242| `templates/result_type.ts` | Result type implementation |243244---245> Source: [mwigge/agent-toolkit-bundle](https://github.com/mwigge/agent-toolkit-bundle) — distributed by [TomeVault](https://tomevault.io).246<!-- tomevault:4.0:skill_md:2026-05-22 -->