TypeScript Production Readiness Checklist: What to Verify Before You Ship
A practical checklist covering TypeScript configuration, runtime safety, CI integration, and type discipline before deploying a production TypeScript app.
Shipping a TypeScript app is not the same as shipping a type-safe app. The language gives you tools. Whether your codebase uses them well is a separate question. Before your next production deployment, run through this checklist to verify your TypeScript setup is actually protecting you.
TypeScript Production Readiness Checklist
Configuration
-
strict: trueis set in tsconfig.json. This enables the eight flags —strictNullChecks,noImplicitAny,strictFunctionTypes, and five others — that provide real type safety. If you inherited a codebase with strict off, plan a migration path. Ship with strict on or accept that TypeScript is providing limited value. -
noUncheckedIndexedAccess: trueis set. This flag is not included instrict: true. Without it, array index access and object key access returnTeven when the value can beundefined. Enable it and fix the errors — they are real bugs. -
noImplicitReturns: trueis set. Ensures every code path through a function with a return type actually returns. Catches the silentundefinedthat slips out when a branch is forgotten. -
skipLibCheckisfalseunless justified. If it istrue, document why. Skipping type checking on declaration files hides real problems in third-party types. -
targetmatches your actual runtime. If you are running Node 22, your target should beES2022or higher. Compiling toES5adds unnecessary code and polyfills. -
moduleResolutionisNodeNextorBundler— notnode. The legacynoderesolution does not handle modern ESM correctly. Update it.
Runtime Validation
-
External data is validated at every ingestion point. JSON from HTTP APIs, data from database queries, webhook payloads, and message queue events are all untyped at runtime. If your application calls
data as SomeTypeanywhere without prior validation, that is an unguarded trust boundary. Every one should use a schema library (Zod, Valibot, Arktype) or explicit checks. -
Environment variables are validated at startup.
process.env.SOME_KEYisstring | undefined. If your application assumes it is always defined, a deployment missing a variable will fail at the point of use — not at startup. Validate all required environment variables when the process boots and throw immediately if any are missing. -
Error handling does not blindly cast
errtoError. Thrown values can be anything. Useerr instanceof Errorbefore accessing.message. WithuseUnknownInCatchVariableson, TypeScript will remind you if you forget.
Type Discipline
-
No
anytypes are used without explicit justification. Search the codebase forany. Some uses are unavoidable (complex third-party interop), but most are avoidable. Each one is a hole in your type coverage. Considerunknowninstead — it forces you to narrow before use. -
Type assertions (
as SomeType) are rare and reviewed. Everyasis a promise you are making to TypeScript. If you are wrong, you get a runtime crash. Find all occurrences and verify each one is genuinely safe or has runtime validation backing it. -
Non-null assertions (
!) are rare. Same reasoning asas. Each!is a suppressed null check. If the value is ever actually null, you get a crash. Replace with explicit guards where possible. -
Shared interfaces and types live in a
types/directory. Centralized type definitions prevent duplication and drift. If the same interface is defined in two places, they will diverge. -
Return types are explicit on public functions. TypeScript infers return types, but annotating them explicitly catches implementation drift. If a function is supposed to return
Promise<User>and you change the implementation, an explicit return type annotation will surface the error immediately.
CI and Build Pipeline
-
tsc --noEmitruns on every pull request. Type checking should be a separate step from building. Run it in CI and block merges on failure. -
Type check is not skipped to speed up CI. Skipping type checks to save build minutes defeats the purpose of using TypeScript. If type checking is slow, investigate project references and incremental builds — not disabling it.
-
The build output is from the same tsconfig that type-checks. If your CI type-checks with one config and builds with another (common in monorepos), divergence is possible. Align them.
-
Tests are type-checked too. If your test files use
ts-jestor Vitest with TypeScript, ensure they are included in the tsconfig. Typed tests surface usage errors and keep test code honest.
Dependencies
-
@types/*packages match the version of the underlying library. A mismatch betweenexpressand@types/expressversions can cause subtle type errors or incorrect inference. Pin them together. -
Dependencies without type definitions are wrapped. If a package ships no
.d.tsfiles and no community types exist, write a minimal declaration file insrc/@types/. Do not let the entire import becomeany.
If any item on this list is an open question for your team, that is where to invest before the next deployment. Clixo helps product teams build TypeScript systems that are genuinely production-ready, not just TypeScript-flavored JavaScript.