Strictness and Checking Options
Strictness and Checking Options
"strict": true is the floor; these flags catch the defects that still slip past it:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitOverride": true,
"verbatimModuleSyntax": true
}
}
noUncheckedIndexedAccess types arr[0] as T | undefined, forcing bounds checks. exactOptionalPropertyTypes stops { a: undefined } from satisfying { a?: string }. verbatimModuleSyntax preserves import type elision exactly as written, which keeps side-effect-only imports from vanishing under isolatedModules transpilers.
Module Resolution and Paths
Module Resolution and Paths
module and moduleResolution must agree with the runtime:
{ "module": "nodenext", "moduleResolution": "nodenext" }
{ "module": "esnext", "moduleResolution": "bundler" }
Under nodenext, relative imports need explicit .js extensions and package exports are honored, matching Node ESM. bundler allows extensionless imports because a bundler resolves them. paths maps aliases for the type checker:
{ "paths": { "@app/*": ["./src/*"] } }
Paths are type-level only — Jest, Vite, and Node need matching alias config or types compile while runtime resolution fails.
Project References and Build Flags
Project References and Build Flags
Project references split a repo into independently built pieces:
{ "compilerOptions": { "composite": true, "declaration": true, "outDir": "dist" },
"references": [{ "path": "../core" }] }
composite requires declaration and a fixed rootDir; consumers then import via .d.ts outputs instead of re-typechecking sources. tsc -b builds the dependency graph in order and skips up-to-date projects (tracked in .tsbuildinfo), which is what makes monorepo typechecking incremental.
Pitfall: references govern TypeScript only — bundlers and test runners still need their own resolution, and a stale outDir after refactoring rootDir produces confusing "file not found" errors.
Quiz
1. What does noUncheckedIndexedAccess change?
2. Why can paths aliases compile in tsc but fail at runtime?
3. What does composite: true enable?
Flashcards
Question
noUncheckedIndexedAccess
Click to reveal answer
Answer
Makes arr[i] T | undefined so missing indexes are handled explicitly.
Question
moduleResolution: nodenext
Click to reveal answer
Answer
Node ESM rules: explicit .js extensions on relative imports, honors package exports.
Question
moduleResolution: bundler
Click to reveal answer
Answer
Extensionless imports allowed because a bundler resolves them at build time.
Question
Composite + references
Click to reveal answer
Answer
declaration-required projects built incrementally with tsc -b, consuming .d.ts outputs.
Question
paths
Click to reveal answer
Answer
Type-checker alias mapping only — mirror it in Jest/Vite/Node or runtime resolution breaks.
Revision Notes
Key Takeaways
- 1. strict plus indexed-access flags catch the defects null checks alone miss
- 2. Choose moduleResolution from the actual runtime, not habit
- 3. Project references make typechecking incremental but do not configure bundlers
Interview Tips
- • State which tool resolves each specifier: tsc, bundler, test runner, or Node
- • Explain why two configs (nodenext vs bundler) can both be right for different packages
Cheat Sheet
strict + noUncheckedIndexedAccess + exactOptionalPropertyTypes; nodenext needs .js extensions, bundler does not; paths is type-only; composite + tsc -b = incremental.
Continue Learning
Before You Start
- No prerequisites listed.