TypeScript in Node Best Practices
TypeScript pays off when strict compile-time checks meet runtime validation at boundaries - not when any leaks through ORM results and request bodies.
Search across all documentation pages
TypeScript pays off when strict compile-time checks meet runtime validation at boundaries - not when any leaks through ORM results and request bodies.
allowJs.any or @ts-ignore without ticket justification.tsc --noEmit and tests in CI - types without tests still ship bugs.strict: true for all new projects. Add stricter flags (noUncheckedIndexedAccess) when team is ready.module / moduleResolution: NodeNext on Node 24 ESM. Matches runtime resolver.tsc --noEmit in CI on every PR. tsx dev alone does not typecheck.dist/ for production containers. CMD ["node", "dist/main.js"] - no tsx in prod image.typescript and @types/node to compatible majors. Align @types/node with Node 24.process.env with Zod at startup. Fail before listening on a port.as Foo on req.body.z.infer - no duplicate interfaces. Single source of truth.unknown until parsed. Even from trusted vendors.import type for type-only imports. Enable verbatimModuleSyntax on new repos.any - use unknown + narrow. ESLint @typescript-eslint/no-explicit-any as error.!) to tests. Production code uses guards or Zod.{ ok: true, value } | { ok: false, error }.@ts-ignore - use @ts-expect-error with ticket and removal date.Request for cross-cutting fields only. Per-route generics for body/params.Promise<void> return. Ensure errors reach framework error hooks.@acme/api-types pattern..js files in typed directories. allowJs is temporary.node:test suites early. Tests lock behavior during JS → TS rename.node:* imports. Safe for React bundlers.Rarely - third-party escape hatches with immediate narrow wrapper. Never in domain logic.
Recommended for new code - catches arr[i] undefined. Noisy on brownfield - enable per directory.
Yes - TS for developers, Zod for runtime data crossing trust boundaries.
Private apps can skip publishing .d.ts - libraries and shared types packages need them.
Prisma types are DB-shaped - map to DTOs before HTTP responses.
Either include **/*.test.ts in main tsconfig or separate tsconfig.test.json - both must typecheck in CI.
strict + ESLint noImplicitAny equivalent rules from typescript-eslint recommended type-checked config.
Yes - config satisfies Config validates object literals without widening - great for static config maps.
Prefer as const + unions or Zod enums - better runtime and tree shaking than TS enum.
Align versions - mismatch causes wrong handler typings.
Use secondary tsconfig.strict.json include glob - expand monthly until main config covers all src.
Zod at Boundaries - canonical env and body patterns.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026