Strict TypeScript with zero-any tolerance, no-unsafe-* lints, floating-promise prevention, and disciplined type-system usage. Use when implementing, debugging, refactoring, or reviewing TypeScript code; resolving type errors; configuring tsconfig/ESLint/Prettier; setting up React/Next/Express patterns; eliminating any/unknown drift; or evaluating advanced generics, conditional types, and inference. Applies to any TypeScript work unless a more specific role overrides.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Strict TypeScript with zero-any tolerance, no-unsafe-* lints, floating-promise prevention, and disciplined type-system usage. Use when implementing, debugging, refactoring, or reviewing TypeScript code; resolving type errors; configuring tsconfig/ESLint/Prettier; setting up React/Next/Express patterns; eliminating any/unknown drift; or evaluating advanced generics, conditional types, and inference. Applies to any TypeScript work unless a more specific role overrides.
TypeScript Pro
Senior-level TypeScript expertise for production projects. Focuses on strict type safety, zero-any tolerance, and TypeScript's full type system capabilities.
When Invoked
Review tsconfig.json and eslint.config.js for project conventions
For build system setup, invoke the just-pro skill (covers just vs make)
Apply type-first development and established project patterns
Core Standards
Required:
Strict mode enabled with all compiler flags
NO explicit or implicit any - use unknown and narrow
NO type assertions to circumvent the type system (as any, as unknown as T)
NO dangling promises - await, return, or void explicitly
All exported functions have explicit return types
ESLint strict-type-checked passes with project configuration
Table-driven tests for multiple cases
Foundational Principles:
Single Responsibility: One module = one purpose, one function = one job
No God Objects: Split large classes/objects; if it has 10+ methods or properties, decompose
Dependency Injection: Pass dependencies via constructor/params, don't instantiate internally
Small Interfaces: Prefer many small types over few large ones; compose with intersection types
Composition over Inheritance: Use object composition and mixins, not deep class hierarchies
Project Setup (TypeScript 5.5+)
Version Management
Pin Node version with mise: mise use node@22 (creates .mise.toml — commit it). Team members run mise install. See mise skill for setup.
New Project Quick Start
# Initialize
npm init -y
npm install -D typescript typescript-eslint @eslint-community/eslint-plugin-eslint-comments eslint-plugin-sonarjs prettier lint-staged vitest @vitest/coverage-v8
# Add scripts to package.json:
npm pkg set scripts.typecheck="tsc --noEmit"
npm pkg set scripts.lint="eslint src/"
npm pkg set scripts.test="vitest run"
npm pkg set scripts.coverage="vitest run --coverage --coverage.thresholds.lines=70 --coverage.thresholds.functions=70 --coverage.thresholds.branches=70 --coverage.thresholds.statements=70"
npm pkg set scripts.check="npm run typecheck && npm run lint && npm run coverage"# Configure lint-staged (formats only staged files on commit)
npm pkg set lint-staged --json '{"*.{ts,tsx}": ["prettier --write"], "*.{json,yml,yaml}": ["prettier --write"]}'# Create .prettierignore (prevent formatting machine-generated and non-TS files)cat > .prettierignore << 'EOF'# ============================================================================# DO NOT ADD SOURCE FILES HERE TO WORK AROUND LINE LENGTH LIMITS.## If prettier expansion pushes a file past max-lines (400) or# max-lines-per-function (60), the file needs to be DECOMPOSED — extract# functions, split into modules, rearchitect. That is the engineering fix.## Adding source files here suppresses formatting without fixing the real# problem. The line limits are design signals, not obstacles to route around.# ============================================================================# Machine-generated / non-source (safe to exclude)
coverage/
dist/
node_modules/
.worktrees/
.timbers/
.beads/
EOF
# Verify
npm run check
Pre-commit Hook
Quality gates run via a git pre-commit hook. With beads 1.0+, hooks live in .beads/hooks/ (committed to git, managed by bd hooks install --beads). Beads, timbers, and your quality gates all coexist in the same hook file via section markers — content outside markers is preserved across reinstalls.
Setup:
bd init (creates .beads/hooks/ and sets core.hooksPath = .beads/hooks)
#!/usr/bin/env sh# --- BEGIN BEADS INTEGRATION v1.0.x --- (managed — do not edit)# ... bd hooks run pre-commit shim ...# --- END BEADS INTEGRATION v1.0.x ---# Quality gates (preserved across reinstalls — outside markers)if [ -f .git/MERGE_HEAD ]; thenecho"Merge commit — skipping lint-staged"else
npx lint-staged
fiifcommand -v just >/dev/null 2>&1 && [ -f justfile ]; then
just check
else
npm run check
fi# --- timbers section (managed by timbers hooks install)# ... timbers hook run pre-commit shim ...# --- end timbers section ---
Why this order: Beads runs first (fast: bd's internal hook handles auto-export+stage of .beads/issues.jsonl). Quality gates run next (slowest, may fail — but bd export already happened, so beads state is captured even if gates fail and the commit aborts). Timbers runs last (post-gate, post-export).
Note on core.hooksPath:bd hooks install --force may set this to an absolute path. Force it relative — worktrees share repo config, and an absolute path won't resolve from a worktree's working dir.
New dev/agent onboarding:git clone <repo> && just setup (which includes just hooks).
In monorepos (multiple packages, possibly mixed languages), adjust the setup:
lint-staged: scoped to TS packages only. Don't format Go/Rust code with Prettier — they have their own formatters (goimports, rustfmt).
# Root package.json (npm workspaces / turborepo):
npm pkg set lint-staged --json '{"packages/web/**/*.{ts,tsx}": ["prettier --write"], "*.{json,yml,yaml}": ["prettier --write"]}'# Or independent packages (no workspaces): install lint-staged per TS package
Pre-commit: lint-staged only, no npm run check. Full quality gates across all packages are too slow for pre-commit. Run lint-staged in the hook, run full gates via just check or CI.
# .beads/hooks/pre-commit (between BEADS markers and timbers section):
npx lint-staged
(beads 1.0+ auto-exports + auto-stages .beads/issues.jsonl on every mutation; the manual export+stage lines older docs showed are no longer needed.)
For mixed-language monorepos without workspaces, detect which packages have staged files:
if git diff --cached --name-only | grep -q '^packages/web/'; then
(cd packages/web && npx lint-staged)
fi
.prettierrc: root-level. Prettier walks up the directory tree, so a single root config covers all TS packages. Use per-package configs only if packages need different formatting.
Required Config Files: Copy references/gitignore → .gitignore, references/prettierrc.json → .prettierrc, then create tsconfig.json and eslint.config.js per the templates below.
Developer Onboarding
git clone <repo> && cd <repo>
just setup # Runs mise trust/install + npm ci
just check # Verify everything works
Or manually:
mise trust && mise install # Get pinned Node version
npm ci # Get dependencies
Why strict configs? Type errors caught at compile time are 10x cheaper than runtime bugs. Strict linting prevents any from leaking through the codebase.
Build System
Invoke the just-pro skill for build system setup. It covers:
Alternative: Use npm scripts directly if just is unavailable.
Quality Assurance
Auto-Fix First - Always try auto-fix before manual fixes:
npx prettier --write src/ # Format changed files
npx eslint src/ --fix # Fixes style, imports, etc.
npx tsc --noEmit # Type check without emit
Verification:
npm run check # typecheck + lint + test
npm audit --omit=dev --audit-level=high # vulnerability check (production deps only)
Or via just (which combines both):
just check
Pre-commit Hook (git hook with lint-staged):
lint-staged formats only staged files via Prettier (no whole-repo formatting)
Then npm run check runs typecheck + lint + test
Blocks commits with formatting issues, type errors, lint violations, or failing tests
Lives in .beads/hooks/pre-commit alongside beads/timbers hooks (not husky, not .git/hooks/)
.prettierignore must exclude .timbers/ and .beads/ — without this, lint-staged reformats timbers JSON during commit, but its stash/restore cycle puts the original format back in the working tree, creating perpetual MM diffs with no semantic content
Linting Configuration
eslint.config.js Template
When creating a new project, copy references/eslint.config.js from this skill — it's the canonical template. Omitting rules allows any to leak through the codebase.
@eslint-community/eslint-comments/no-restricted-disable blocks disabling type-safety, promise, and complexity rules without an explicit override
Tests (**/*.test.ts, **/*.spec.ts) relax any, complexity, and line limits.
Responding to Limit Violations
These limits exist to improve code architecture, not to be gamed. When a file or function exceeds a limit, the correct response is to decompose by responsibility — not to make the code fit by any means necessary.
Extract each into a well-named function or module — the function name itself documents what the section does
Place extracted code in a companion file in the same directory (e.g., order-service.ts → order-validation.ts, order-transforms.ts)
When extraction is costly (many locals to pass), use a context/options object. If splitting would duplicate state, the code may need a different decomposition axis (by entity rather than by phase).
Prohibited responses to limit violations:
Combining statements onto single lines to dodge file/function length limits (max-len at 120 catches this — the line limit and file limit work together)
Removing or shortening comments
Compressing whitespace or collapsing readable formatting
Shortening descriptive variable/function names
Inlining helper functions to reduce function count
Adding source files to .prettierignore so prettier won't expand them back
Any of these trades one problem (length) for a worse one (readability). The goal is clean architecture, not metric compliance. Prettier enforces consistent formatting, so compressed code will be expanded back to its readable form — and max-len prevents the line-combining workaround entirely. Extraction is the only sustainable fix.
Enforced Limits
Limit
Value
Purpose
max-len
120 chars
Prevent line-combining to dodge file/function limits
max-lines
400 code
Prevent god modules (comments excluded)
max-lines-per-function
60
Single responsibility
complexity
10
Cyclomatic complexity (branching paths)
sonarjs/cognitive-complexity
15
Cognitive complexity (perceived difficulty)
max-depth
4
Avoid arrow code
max-params
4
Use options objects
Critical rules cannot be disabled via eslint-disable comments - the config blocks it.