Ts strict
Claude Code plugin marketplace — skills, slash commands, and subagents for TypeScript tooling, codebase auditing, design exploration, and developer workflows
npx -y skills add fntune/skills --skill ts-strictAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Enable TypeScript strict mode and Biome strict lint rules in an existing codebase using an infrastructure-first strategy. Use when the user asks to: enable strict TypeScript, configure Biome strict linting, fix type safety, migrate to strict mode, enable noExplicitAny / noUnusedVariables / noNonNullAssertion, or tighten type checking. Triggers on: "enable strict", "strict mode", "strict types", "strict biome", "biome strict", "fix type safety", "tighten types", "noExplicitAny".
SKILL.md
12.5 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it
TypeScript Strict Migration
Migrate a codebase to strict TypeScript and Biome lint rules using an infrastructure-first approach. Treat type errors as symptoms of missing type architecture, not individual problems.
Strategy: Infrastructure First, Rules Last
0. Baseline -> Measure tsc --strict errors per flag
1. Audit -> Identify patterns producing `any` and weak types
2. Fix -> Define interfaces, replace raw queries, fix return types
3. Enable -> Turn on tsconfig flags incrementally, then Biome rules
4. Clean -> Fix remaining localized issues
Never do bulk mechanical replacements (any -> Record<string, unknown>). That trades one
form of "I don't know the type" for another and creates cascading downstream errors.
Phase 0: Baseline
Measure current error counts per strict flag before touching any code:
# Total strict errors
tsc --noEmit --strict 2>&1 | tail -1
# Per-flag breakdown (strict family)
tsc --noEmit --noImplicitAny 2>&1 | tail -1
tsc --noEmit --strictNullChecks 2>&1 | tail -1
tsc --noEmit --strictFunctionTypes 2>&1 | tail -1
tsc --noEmit --strictPropertyInitialization --strictNullChecks 2>&1 | tail -1
# Beyond-strict flags (not included in strict: true)
tsc --noEmit --noUncheckedIndexedAccess 2>&1 | tail -1
Note: strictPropertyInitialization requires strictNullChecks to be meaningful.
Present a table and get user approval on enable order:
| Flag | Errors | Recommended order |
|---|---|---|
noImplicitAny | N | 1st — easiest wins |
strictNullChecks | N | 2nd — biggest safety gain |
strictFunctionTypes | N | 3rd — usually few errors |
strictPropertyInitialization | N | 4th — class-heavy codebases |
Full strict: true | N | Last — enables all remaining |
strict: true also enables strictBindCallApply, noImplicitThis, alwaysStrict, and
useUnknownInCatchVariables — these rarely produce many errors but measure them if the
gap between individual flags and full strict is large.
Beyond strict (not included in strict: true — must remain as separate flags):
| Flag | Purpose |
|---|---|
noUncheckedIndexedAccess | arr[0] and obj[key] return T | undefined — highest friction, biggest safety gain after strictNullChecks |
exactOptionalPropertyTypes | { a?: string } distinguishes "missing" from "explicitly undefined" |
noUncheckedSideEffectImports | Errors on unresolvable side-effect imports like import "./missing" (TS 5.6+) |
Phase 1: Audit
Catalog every any and weak type by root cause category. See
references/audit-categories.md for the common categories.
# Count current violations before touching anything
biome lint . 2>&1 | grep -c 'noExplicitAny'
biome lint . 2>&1 | grep -c 'noUnusedVariables'
Group violations by file and root cause. Present a summary table:
| Root cause | Count | Fix approach |
|---|---|---|
| Untyped API responses | N | Define response interfaces |
Raw SQL / db.execute() | N | Replace with typed ORM queries |
Partial<T> too loose | N | Use Pick<T, ...> for known fields |
| External JWT/webhook payloads | N | Validate at boundary with Zod (or typeof) |
| Callback params | N | Type the callback signature |
Unused _-prefixed params | N | Configure rule to ignore ^_ pattern |
Get user approval on the plan before proceeding.
Phase 2: Fix Type Infrastructure
Work through root causes from highest-impact to lowest. For each category:
- Define the missing type at its source (API client, ORM query, service layer)
- Verify downstream usage compiles without casts or bandaids
- Run build to confirm no regressions
Patterns by category
See references/fix-patterns.md for detailed patterns covering:
- API response interfaces
- ORM typed queries (Drizzle, Prisma)
- External data boundary validation
- Return type tightening (
Partial->Pick) - Callback and event handler typing
satisfiesfor config/literal objects- Discriminated union exhaustiveness (
assertExhaustive)
For Drizzle + Zod v4 full-stack type propagation (DB schema → API contracts → frontend), see references/drizzle-zod.md.
Principles
- Fix the type at its source, not at its usage site
- Every
as Xcast or?? fallbackat a usage site signals a missing upstream type - Prefer
typeofnarrowing over type assertions for external data - Use
Pick<T, fields>overPartial<T>when you know which fields are selected - Replace raw SQL with typed ORM queries whenever the ORM supports it
Phase 3: Enable Rules
Only after infrastructure fixes are in place.
3a. tsconfig strict flags
Enable flags incrementally in the order from Phase 0. After each flag:
- Add the flag to
tsconfig.json - Run
tsc --noEmit— fix any new errors - Commit before enabling the next flag
Once all individual flags pass, switch to "strict": true and remove the individual strict-family
flags. Keep beyond-strict flags (noUncheckedIndexedAccess, exactOptionalPropertyTypes, etc.)
as separate entries — they are not included in strict: true.
3b. Biome strict rules
Biome is a single Rust binary that handles linting and formatting — no plugins, no tsc dependency.
Its recommended preset enables a sensible baseline (style rules default to warn; override to
error for strict enforcement).
Key rules for strict TypeScript:
| Rule | Category | What it catches |
|---|---|---|
noExplicitAny | suspicious | Explicit any type annotations |
noUnusedVariables | correctness | Unused variables and type params |
noUnusedImports | correctness | Unused import statements |
noUnusedFunctionParameters | correctness | Unused function parameters |
noNonNullAssertion | style | ! postfix assertions |
useConst | style | let where const suffices |
useImportType | style | Missing import type for type-only imports |
noFloatingPromises | types | Unawaited promises (v2.4+, type-aware) |
Type-aware rules: Biome v2 added file scanning for type inference. Rules that need type info
live in the types domain (v2.4+; earlier versions used project). Currently noFloatingPromises
is the main type-aware rule. Deep type-checked rules like no-unsafe-assignment and
no-unnecessary-type-assertion don't have Biome equivalents yet — tsc --noEmit with strict
flags covers the type safety that Biome can't.
Strict production config with test file overrides:
{
"$schema": "https://biomejs.dev/schemas/<version>/schema.json",
"linter": {
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error",
"noUnusedImports": "error",
"noUnusedFunctionParameters": "error"
},
"suspicious": {
"noExplicitAny": "error",
"noDoubleEquals": "error"
},
"style": {
"noNonNullAssertion": "error",
"useConst": "error",
"useImportType": "error"
}
}
},
"overrides": [
{
"includes": ["**/__tests__/**", "**/*.test.ts", "**/*.test.tsx"],
"linter": {
"rules": {
"suspicious": { "noExplicitAny": "off" },
"style": { "noNonNullAssertion": "off" },
"complexity": { "noBannedTypes": "off" }
}
}
}
]
}
After enabling:
- Run
biome lint .— expect most violations already resolved from Phase 2 - Run
biome lint --write .for auto-fixable issues (unused imports,let→const, etc.)
Suppression guidance
TypeScript:
- Never use
@ts-ignore— it silently persists after the underlying error is fixed - Use
@ts-expect-errorwith a description when suppression is genuinely needed:// @ts-expect-error -- library types don't expose the overload we need@ts-expect-errorerrors when the suppressed issue disappears, preventing stale suppressions
Biome — reason is mandatory (Biome rejects bare suppressions):
// biome-ignore lint/suspicious/noExplicitAny: legacy API requires any
const result: any = legacyFunction();
Monorepo considerations
In a multi-package repo, strict migration touches shared config infrastructure:
Shared base tsconfig — define strict flags once in a root tsconfig.base.json, have every
package extend it. Redundantly repeating "strict": true in per-package configs is fine as an
explicit marker, but the actual flag set should live in one place.
// tsconfig.base.json (root)
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"isolatedModules": true,
"moduleResolution": "bundler"
}
}
// packages/foo/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "./dist", "rootDir": "./src" },
"include": ["src/**/*"]
}
Biome in monorepos — a single root biome.json applies to all packages automatically.
No per-package config needed. Use overrides with includes globs for package-specific
rule relaxation (e.g., animation packages, generated code).
Cross-package type resolution — two strategies, pick one:
-
Build-first (Turborepo/Nx): upstream packages build
.d.tsintodist/, downstream packages consume them viapackage.json"types"field. Typecheck task depends on^build(upstream builds run first). No project references needed. -
Project references (
tsc --build): setcomposite: truein each package tsconfig, add a"references"array in the root. Faster incremental builds but more config overhead.
Most Turborepo/Bun/pnpm monorepos use strategy 1. Project references are mainly useful when
you want single-command tsc --build without a task runner.
Baseline per-package: in Phase 0, measure errors per package to find the worst offenders:
# Run from monorepo root
for pkg in packages/*/; do
echo "=== $pkg ==="
tsc --noEmit --project "$pkg/tsconfig.json" --strict 2>&1 | tail -1
done
Enable flags root-first: add the flag to tsconfig.base.json, then fix errors package by
package (core/utils first, then infrastructure, then domain, then frontend). This follows the
dependency graph — fixing upstream packages eliminates cascading errors downstream.
Selective typecheck configs: for large packages with generated or third-party code (e.g.,
shadcn components), create a tsconfig.typecheck.json that narrows include to your code only:
// packages/ui/tsconfig.typecheck.json
{
"extends": "./tsconfig.json",
"include": ["src/auth/**", "src/billing/**"],
"exclude": ["src/primitives/**", "src/composed/**"]
}
Then in package.json: "typecheck": "tsc --noEmit --project tsconfig.typecheck.json".
Phase 4: Clean Remaining Issues
Fix remaining violations individually. These should be localized (not cascading) because the type infrastructure is already correct. Common remaining fixes:
- Remove truly dead code (unused variables without
_prefix) - Add
_prefix to intentionally unused params (callbacks, route handlers) - Replace remaining
anywithunknown+ type guard for genuinely dynamic data - Add
!assertions only when TypeScript can't infer non-null from control flow (rare)
Verification
tsc --noEmit # Zero type errors
biome lint . # Zero lint errors
pnpm build # Full build passes
CI enforcement
Add to pipeline to prevent regression:
- run: tsc --noEmit
- run: biome ci .
biome ci is the CI-specific command — it checks format + lint without writing files,
and exits non-zero on any violation.
Anti-patterns
- Bulk
any->Record<string, unknown>: Creates cascading errors, no type safety gain as anyto silence errors: Hides real type mismatches- Double casts (
as unknown as T): Acceptable only at ORM/serialization boundaries @ts-ignore: Use@ts-expect-errorwith a description instead; it auto-errors when the issue is fixed- Parallel bulk-fix agents: Produces mechanical patches; audit and plan first instead
What ships with it: 3 files
32.3 KB alongside SKILL.md
references/
- audit-categories.md4.3 KB
- drizzle-zod.md10.7 KB
- fix-patterns.md17.3 KB