Write idiomatic, strict TypeScript
Add TypeScript that type-checks under strict mode, models data precisely, and matches
the repo's existing idioms — provably correct, not just compiling.
Steps
- Read the lore first. Call
search_lore (Memory MCP) for the repo's TS
conventions and respect its tsconfig.json (never weaken strict or paths),
eslint/prettier config, and module style (ESM vs CJS).
- Find a sibling module and copy its patterns — file layout, export style
(prefer named exports), error handling, and how types are organised.
- Type precisely. Model nullability explicitly; prefer
unknown over any
(justify any any in a comment); use discriminated unions and satisfies over
type assertions. Validate external data at the boundary (e.g. Zod) rather than casting.
- Get async right. Use
async/await over .then() chains; await or
deliberately handle every promise; never leave a floating promise or empty catch.
- Keep imports tidy. Order external → internal aliases → relative, alphabetised
within groups;
const over let, never var.
- Type-check and test. Run the project's type-check (e.g.
tsc --noEmit) and
tests; fix the cause of errors rather than casting them away.
- Verify + evidence. Run tests + lint, record
test_output via the
record-evidence skill, and submit for review.
Build / Test
- Type check:
tsc --noEmit (or the repo's script) — fix the cause, never widen tsconfig.
- Lint/format: the repo's ESLint + Prettier scripts; fix, don't suppress.
- Tests: the repo's runner (Vitest/Jest); coverage via its coverage script.
- The DoD is verified by the repo's configured test/coverage commands — run them and
record the output; a green type-check + tested run is the evidence.
Review checklist (a TS reviewer must check)
- Strict mode intact — no weakened
tsconfig, no stray @ts-ignore/@ts-expect-error
without justification.
unknown over any — every any is justified in a comment; satisfies used instead
of type assertions where possible.
- External input validated at the boundary (e.g. Zod), not cast.
- No floating promises, no empty catch blocks — every promise is awaited/handled and
errors are handled or rethrown.
- Named exports by default; imports ordered external → internal alias → relative,
alphabetised;
const over let, no var.
- Lint/format clean — matches the repo's ESLint + Prettier config exactly.
Rules
- Strict mode stays on; no widening
tsconfig to silence errors.
unknown over any; satisfies over assertions; validate external input.
- No floating promises, no empty catch blocks — handle or rethrow explicitly.
- Match the repo's lint/format config exactly; named exports by default.
Capture lore
This skill is one of the places durable, reusable knowledge naturally surfaces:
A TypeScript/stack convention this repo enforces beyond the obvious — an import-ordering rule, a type-modelling pattern, or a lint/tsconfig constraint. That kind of fact is lore. Capture it via the lore-capture
protocol in your brief (CLAUDE.factory.md, step 11 "Memory contribution"):
call the Memory MCP suggest_lore once at the close of your work — reusable
conventions, gotchas, decisions, and boundaries only, never per-ticket trivia.
1---2name: typescript-conventions3description: Use when a ticket adds or changes TypeScript/JavaScript code and it must follow the repo's TS conventions — strict typing, async correctness, module/import hygiene, and idiomatic patterns. Invoke for "add this in TypeScript", "fix the type errors", "tighten the types on X", or as the language pack for any TS/JS change.4---56# Write idiomatic, strict TypeScript78Add TypeScript that type-checks under strict mode, models data precisely, and matches9the repo's existing idioms — provably correct, not just compiling.1011## Steps12131. **Read the lore first.** Call `search_lore` (Memory MCP) for the repo's TS14 conventions and respect its `tsconfig.json` (never weaken `strict` or `paths`),15 `eslint`/`prettier` config, and module style (ESM vs CJS).162. **Find a sibling module** and copy its patterns — file layout, export style17 (prefer named exports), error handling, and how types are organised.183. **Type precisely.** Model nullability explicitly; prefer `unknown` over `any`19 (justify any `any` in a comment); use discriminated unions and `satisfies` over20 type assertions. Validate external data at the boundary (e.g. Zod) rather than casting.214. **Get async right.** Use `async/await` over `.then()` chains; `await` or22 deliberately handle every promise; never leave a floating promise or empty catch.235. **Keep imports tidy.** Order external → internal aliases → relative, alphabetised24 within groups; `const` over `let`, never `var`.256. **Type-check and test.** Run the project's type-check (e.g. `tsc --noEmit`) and26 tests; fix the cause of errors rather than casting them away.277. **Verify + evidence.** Run tests + lint, record `test_output` via the28 `record-evidence` skill, and submit for review.2930## Build / Test3132- **Type check:** `tsc --noEmit` (or the repo's script) — fix the cause, never widen `tsconfig`.33- **Lint/format:** the repo's ESLint + Prettier scripts; fix, don't suppress.34- **Tests:** the repo's runner (Vitest/Jest); coverage via its coverage script.35- The DoD is verified by the repo's configured test/coverage commands — run them and36 record the output; a green type-check + tested run is the evidence.3738## Review checklist (a TS reviewer must check)3940- **Strict mode intact** — no weakened `tsconfig`, no stray `@ts-ignore`/`@ts-expect-error`41 without justification.42- **`unknown` over `any`** — every `any` is justified in a comment; `satisfies` used instead43 of type assertions where possible.44- **External input validated** at the boundary (e.g. Zod), not cast.45- **No floating promises**, no empty catch blocks — every promise is awaited/handled and46 errors are handled or rethrown.47- **Named exports** by default; imports ordered external → internal alias → relative,48 alphabetised; `const` over `let`, no `var`.49- **Lint/format clean** — matches the repo's ESLint + Prettier config exactly.5051## Rules5253- Strict mode stays on; no widening `tsconfig` to silence errors.54- `unknown` over `any`; `satisfies` over assertions; validate external input.55- No floating promises, no empty catch blocks — handle or rethrow explicitly.56- Match the repo's lint/format config exactly; named exports by default.5758## Capture lore5960This skill is one of the places durable, reusable knowledge naturally surfaces:61**A TypeScript/stack convention this repo enforces beyond the obvious — an import-ordering rule, a type-modelling pattern, or a lint/tsconfig constraint.** That kind of fact is *lore*. Capture it via the **lore-capture62protocol in your brief** (`CLAUDE.factory.md`, step 11 "Memory contribution"):63call the Memory MCP `suggest_lore` once at the close of your work — reusable64conventions, gotchas, decisions, and boundaries only, never per-ticket trivia.