ls-typescript-code-quality · v1.0 · 2026-07-15 · sha256 e3068ddc604e52e2
ls-typescript-code-quality v1.0A
Immutable. This exact content never changes and is served at /api/v1/blob/e3068ddc604e52e2.
--- name: ls-typescript-code-quality description: "Guide TypeScript code quality work. Use when touching TypeScript, TSX, tsconfig, typed ESLint or Biome config, Node TypeScript scripts, or TypeScript-heavy framework code." metadata: version: "1.0" --- # TypeScript Code Quality Use this skill when reviewing or changing TypeScript projects, TSX UI code, TypeScript configuration, typed linting, Node TypeScript scripts, or frameworks whose behavior depends on TypeScript tooling. ## Start With The Pinned Toolchain Before recommending upgrades or changing compiler/linter settings, inspect the project's actual toolchain: - `package.json`: package manager, scripts, `type`, `engines`, framework packages, TypeScript, ESLint, typescript-eslint, Biome, build tools, and test runners. - Lockfile: confirm the installed versions rather than assuming the manifest was resolved recently. - TypeScript configs: `tsconfig.json`, project references, framework-specific configs, and separate lint/test/build configs. - Framework version: Next.js, Vite, Angular, SvelteKit, Remix, NestJS, or other toolchains may pin TypeScript, Node, module resolution, JSX, or build behavior. - Existing commands: prefer the repo's scripts (`typecheck`, `lint`, `test`, `build`) over ad hoc runner invocations. Do not upgrade TypeScript, Node, framework packages, or lint presets just because a newer version exists. Treat framework and lockfile compatibility as the first constraint. When a TypeScript project needs a Node runtime baseline, target the latest available production LTS line that the project's framework and deployment platform support. Prefer Active LTS over Maintenance LTS, and do not choose a Current release line for production unless the project explicitly requires it. ## Type Safety Rules - Keep `strict` enabled for new code unless the project has a documented staged migration plan. - Consider `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, and `noFallthroughCasesInSwitch` when the project can absorb the added friction. - Avoid `any`, double assertions, broad object types, and `Function`. If an escape hatch is necessary, keep it local and add a short reason. - Prefer discriminated unions, `unknown` plus narrowing, branded IDs where useful, and explicit return types on exported APIs. - Validate external boundaries at runtime: CLI args, env vars, JSON, HTTP payloads, database rows, localStorage, queue messages, and plugin input. - Keep generated types, schema validators, and API clients in sync. Do not edit generated files by hand unless the repo explicitly does so. ## Async, Errors, And Boundaries - Await promises intentionally; do not leave floating promises unless a lint rule and local pattern mark them safe. - Preserve causal error context with `cause` or wrapped messages when crossing module boundaries. - Model recoverable failures as typed results only when that pattern already exists; otherwise use exceptions with actionable messages. - Add cancellation, timeout, and cleanup behavior for long-running IO. - Keep framework server/client boundaries clear. Do not import server-only modules into browser bundles or browser globals into Node-only code. ## Linting And Formatting - Prefer typed linting when the project already uses ESLint with typescript-eslint and performance is acceptable. - For typescript-eslint v8 and newer, prefer `parserOptions.projectService: true` unless the repo already has a stable `project` or `tsconfig.eslint.json` setup. - With Biome, preserve the existing formatter/linter contract. If Biome is the only linter, keep `tsc --noEmit` or the framework type checker as the type safety gate. - Keep formatting changes separate from semantic changes when the diff would be noisy. - Do not replace a working ESLint/Biome setup without a project-specific reason. ## Module And Import Hygiene - Match the repo's module system: CommonJS, ESM, `nodenext`, `bundler`, or framework-specific defaults. - Do not change `module`, `moduleResolution`, `jsx`, `paths`, or package `exports` without checking runtime and bundler behavior. - Prefer `import type` for type-only imports, especially when native Node type stripping, `verbatimModuleSyntax`, or isolated emit is in play. - Keep path aliases consistent across TypeScript, bundler, test runner, and runtime. If one tool cannot resolve an alias, fix the shared config rather than scattering relative imports. - Avoid deep imports from package internals unless the package documents them. ## Size And Maintainability Review Use heuristics to decide where to focus, not as hard rules: - Files over about 300 lines deserve a scan for mixed responsibilities. - Functions over about 50 lines deserve a scan for hidden phases, nested control flow, and implicit state. - Types that require repeated assertions or helper overloads may need a simpler domain model. - React/TSX components that mix fetching, state orchestration, rendering, and formatting are good candidates for extraction. - Shared utility modules should have focused names and low dependency fan-in. ## Validation Prefer repo-native scripts, in this order when available: ```bash npm run typecheck npm run lint npm test npm run build ``` Adapt for the package manager (`pnpm`, `yarn`, `bun`) and monorepo task runner already in use. If scripts are missing but dependencies exist, fall back to the least surprising direct commands, such as: ```bash npx tsc --noEmit npx eslint . npx vitest run ``` For framework projects, also run the framework build or checker that the repo uses in CI. Record any skipped checks and why. ## Reference - [TypeScript quality standards snapshot](./references/typescript-quality-standards.md) ## Strict Mode Refresh Note For strict-mode work, inspect the current `tsconfig` inheritance tree before changing compiler options. Treat `strict` as the umbrella setting, and evaluate stricter flags such as `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` only when the project can absorb the migration.