Tighten TypeScript Types
Improve the smallest changed surface while preserving runtime behavior and supported consumers. Types must describe evidence, not hide uncertainty.
Set the boundary
- Read repository instructions, the installed compiler version, applicable
tsconfig, configured checks, and the task diff.
- Use user-named files when supplied; otherwise start with changed TypeScript files.
- Trace only the imported/exported interfaces needed to understand those files. Do not survey the whole repository by default.
- Record public declarations, runtime behavior, and consumer compatibility that must remain stable.
Tighten in evidence order
- Replace boundary
any with unknown, then validate or narrow before use.
- Let inference handle honest local values; annotate exported, recursive, overloaded, callback, and serialization boundaries where it improves the contract.
- Make container elements, keys, return values, optionality, and discriminants precise.
- Prefer control-flow narrowing, predicates that perform real runtime checks, discriminated unions, and small typed adapters over assertions.
- Use
satisfies to check values without discarding useful inference.
- Use an assertion only when a runtime fact is established outside TypeScript's model; keep it at that boundary and explain the fact.
- Never invent precision for dynamic legacy data. Keep uncertainty visible until validation.
Public compatibility does not require preserving any automatically. A narrower, truthful declaration may be acceptable only after compiling supported consumers and confirming the intended API contract; otherwise tighten behind the existing boundary.
Expand scope only when required
Expand beyond the selected files only for a directly used declaration that prevents an honest local type, a necessary consumer fixture, or a focused regression test. Do not clean unrelated any, assertions, ignores, formatting, or legacy modules. Report pre-existing external errors separately.
Verify
Run the configured focused typecheck and tests, then required repository checks. When exported types change, emit declarations if applicable and compile a supported external consumer. Review the diff for runtime changes, public API drift, formatting churn, new suppressions, and assertions.
Common mistakes
| Mistake |
Correction |
Replacing any with an asserted domain type |
Use unknown and validate at the boundary |
Freezing a public any without examining consumers |
Test whether a truthful type is compatible |
| Fixing every nearby legacy error |
Limit edits to necessary interfaces and report the rest |
| Adding generic machinery for local inference |
Prefer the compiler's existing inference |
Using @ts-ignore to finish the pass |
Resolve the cause or leave the uncertainty explicit |
1---2name: tighten-typescript-types3description: Use when tightening annotations in existing TypeScript, removing avoidable any or assertions, improving changed-file types, or reducing compiler errors without broad refactoring.4---56# Tighten TypeScript Types78Improve the smallest changed surface while preserving runtime behavior and supported consumers. Types must describe evidence, not hide uncertainty.910## Set the boundary11121. Read repository instructions, the installed compiler version, applicable `tsconfig`, configured checks, and the task diff.132. Use user-named files when supplied; otherwise start with changed TypeScript files.143. Trace only the imported/exported interfaces needed to understand those files. Do not survey the whole repository by default.154. Record public declarations, runtime behavior, and consumer compatibility that must remain stable.1617## Tighten in evidence order1819- Replace boundary `any` with `unknown`, then validate or narrow before use.20- Let inference handle honest local values; annotate exported, recursive, overloaded, callback, and serialization boundaries where it improves the contract.21- Make container elements, keys, return values, optionality, and discriminants precise.22- Prefer control-flow narrowing, predicates that perform real runtime checks, discriminated unions, and small typed adapters over assertions.23- Use `satisfies` to check values without discarding useful inference.24- Use an assertion only when a runtime fact is established outside TypeScript's model; keep it at that boundary and explain the fact.25- Never invent precision for dynamic legacy data. Keep uncertainty visible until validation.2627Public compatibility does not require preserving `any` automatically. A narrower, truthful declaration may be acceptable only after compiling supported consumers and confirming the intended API contract; otherwise tighten behind the existing boundary.2829## Expand scope only when required3031Expand beyond the selected files only for a directly used declaration that prevents an honest local type, a necessary consumer fixture, or a focused regression test. Do not clean unrelated `any`, assertions, ignores, formatting, or legacy modules. Report pre-existing external errors separately.3233## Verify3435Run the configured focused typecheck and tests, then required repository checks. When exported types change, emit declarations if applicable and compile a supported external consumer. Review the diff for runtime changes, public API drift, formatting churn, new suppressions, and assertions.3637## Common mistakes3839| Mistake | Correction |40|---|---|41| Replacing `any` with an asserted domain type | Use `unknown` and validate at the boundary |42| Freezing a public `any` without examining consumers | Test whether a truthful type is compatible |43| Fixing every nearby legacy error | Limit edits to necessary interfaces and report the rest |44| Adding generic machinery for local inference | Prefer the compiler's existing inference |45| Using `@ts-ignore` to finish the pass | Resolve the cause or leave the uncertainty explicit |