Skip to main content

Best Practices

Practical TSConfig guidance for Nova that uses small, composable preset chains. Favor explicit wiring and predictable compiler behavior.

Dos and Don'ts

DO: Order presets intentionally
  • What: Use a layered "extends" chain in this order: essentials → strict → environment/framework → platform → tool → your custom overrides.
  • Why: The base loads first; the child overrides it. A clear order keeps policy layered and reviewable.
DO: Pair module with moduleResolution correctly
  • What: Keep them in sync by using "module": "nodenext" with "moduleResolution": "nodenext" for Node ESM, or "module": "esnext" with "moduleResolution": "bundler" for bundlers.
  • Why: Mismatched values make TypeScript and your runtime resolve imports differently, which causes "cannot find module" errors. Pairing keeps resolution consistent.
DO: Pair baseUrl with paths
  • What: Set baseUrl when you define import aliases in paths.
  • Why: paths relies on baseUrl. Editors and builds need both to resolve aliases correctly.
DO: Path-related settings belong in the app's tsconfig.json
  • What: Path-related settings like baseUrl, paths, rootDir, outDir, include, and exclude belong in the app's tsconfig.json file, not in Nova presets.
  • Why: TypeScript evaluates these against the file's location. Local wiring avoids resolution mistakes across different repos.
DO: Declare ambient types explicitly
  • What: Use types to list the type packages you installed (e.g., @types/node, @types/react).
  • Why: Makes type sources explicit and under the app's control. Reduces surprises from transitive @types dependencies.
DO: Configure type-checking when a bundler transpiles
  • What: If your project does not use tsc to build, set "isolatedModules": true and "noEmit": true in the app's tsconfig.json.
  • Why: Bundlers and frameworks compile each file independently. isolatedModules enforces per-file safety. noEmit prevents TypeScript from writing JavaScript when another tool already emits output.
DON'T: Assume arrays merge/spread like JavaScript
  • What: Do not expect array settings like lib to spread values from the base.
  • Why: In tsconfig, these arrays replace the parent. This is a config limitation, not JS behavior.
DON'T: Turn on cache-style settings
  • What: Avoid settings that create unpredictability like incremental, composite, and assumeChangesOnlyAffectDirectDependencies in app tsconfig.json files.
  • Why: These introduce cache drift across environments. Prefer deterministic builds.
DON'T: Force typeRoots unless required
  • What: Do not set typeRoots without a strong reason.
  • Why: It limits which @types packages are visible. Defaults usually work best.

Troubleshooting

Find issues by using the command below to print the effective config:

tsc --showConfig --project ./path/to/tsconfig.json