# TypeScript Tooling — Derived Application > Applies Atelier's domain principles to TypeScript tooling specifically. > Derives from `domains/` docs; introduces no new P-rules (D-063). > See `languages/typescript.md` for the language first-principles stub. ## tsc and tsconfig Discipline (DevOps P2 Automation, DevOps P1 Reproducibility) - **`strict: true` is the floor, not the ceiling:** it enables `strictNullChecks`, `noImplicitAny`, `strictFunctionTypes`, and more. Disable sub-flags only with a justification comment. - **`tsc --noEmit` in CI:** type-checking is a build gate; emission is the bundler's job. Separate the two so a type error fails CI even when the bundler would have succeeded. - **`tsconfig` is per-project, not inherited verbatim:** a shared base (`extends`) encodes org defaults; each project overrides the deltas it needs. Avoids the "one monoreto-config-fits-all" trap. - **`noUncheckedIndexedAccess` for safety:** `arr[i]` becomes `T | undefined`, forcing narrowing. Costs little, prevents a class of out-of-bounds deref bugs. - **Applies `devops/P1` (reproducibility):** pinned `typescript` version in `package.json` and `lockfile` ensure every CI run type-checks against the same compiler. ```jsonc // tsconfig.json — base { "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noEmit": true, "moduleResolution": "bundler", "isolatedModules": true } } ``` ## ESLint and @typescript-eslint (DevOps P2 Automation, Documentation P9 Living Documents) - **ESLint with `@typescript-eslint` strict ruleset:** `recommended-type-checked` enables rules that require the type checker (`no-floating-promises`, `no-misused-promises`). - **Rules encode decisions, not taste:** every custom rule in the config has a one-line `// reason:` comment linking to the principle it enforces. This makes the config a living document (Documentation P9). - **Format is Prettier's job; ESLint lints:** `eslint-config-prettier` disables conflicting format rules. Do not relitigate formatting in code review. - **`no-floating-promises` enforces `concurrency/P8` (timeout discipline):** an un-awaited `Promise` is a fire-and-forget that swallows errors and timeouts. The rule forces `.catch()` or `await`. ```jsonc // .eslintrc.json { "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked", "prettier" ], "parserOptions": { "project": "./tsconfig.json" }, "rules": { // reason: enforce Concurrency P8 — no un-awaited promises "@typescript-eslint/no-floating-promises": "error", // reason: enforce Data P7 — no `any` escaping the type checker "@typescript-eslint/no-explicit-any": "error" } } ``` ## Project References and ts-jest (DevOps P2 Automation, C6 Composability) - **Project references for monorepos:** `composite: true` + `references` let `tsc --build` incrementally type-check only changed projects, and enforce the dependency graph at the type level. - **`paths` aliases mirror the import structure:** `@app/*` → `src/*`. Configure once in `tsconfig`, mirror in the bundler and the test runner so all three agree. - **`ts-jest` (or `vitest`) with `isolatedModules: true`:** each test file is type-checked in isolation, matching how the bundler transpiles. Catches the "passes in `tsc` but fails in the bundler" gap. - **Applies `devops/P2`:** the build pipeline (tsc → lint → test → bundle) is automated; a developer never runs a manual sequence. ```jsonc // tsconfig.references.json { "files": [], "references": [ { "path": "./packages/core" }, { "path": "./packages/api" }, { "path": "./packages/web" } ] } ``` ## Lockfile and Reproducible Install (DevOps P1 Reproducibility) - **`npm ci` in CI, not `npm install`:** `ci` reads the lockfile exactly and fails on drift. `install` mutates the lockfile. - **Lockfile committed for applications:** for libraries, commit `package-lock.json` for CI reproducibility even though consumers resolve their own tree. - **No floating ranges in `package.json`:** `^` and `~` are CI's job to resolve; pin the resolved version in the lockfile. An unpinned `*` is a supply-chain attack surface. ```bash # CI install step — deterministic npm ci # Type-check gate npx tsc --noEmit # Lint gate npx eslint . ``` ## Documentation in the Pipeline (Documentation P1 Documentation is Code, DevOps P9 Documentation in the Pipeline) - **Type-checked JSDoc:** `typedoc` (or `TypeDoc`) generates API docs from `tsdoc` comments. The compiler enforces that `@param` names match real parameters. - **`@example` blocks are compiled:** a `tsdoc` `@example` fenced block is type-checked as part of the doc build. Stale examples fail the pipeline (Documentation P1 — docs are code). - **README badges reflect CI status:** the build/lint/test/type-check gates are the source of truth; badges surface them. Do not hand-edit status tables. ```typescript /** * Fetch a user by ID. * * @param id - a branded UserId (see ts-types.md). * @throws {NotFoundError} if the user does not exist. * @example * ```ts * const u = await getUser(userId('abc')); * ``` */ async function getUser(id: UserId): Promise { /* ... */ } ``` ## Cross-References - `domains/devops/ci-cd.md` — the pipeline gates that host tsc/ESLint/ts-jest. - `domains/devops/first-principles.md` — DevOps P1 Reproducibility, P2 Automation. - `domains/documentation/first-principles.md` — Documentation P1 Documentation is Code. - `languages/ts-types.md` — the type rules ESLint enforces reference this doc. - `languages/ts-testing.md` — the test-runner config (`ts-jest`/`vitest`) detailed here.