Quick Overview
Project references let each package build and cache independently, so touching one does not recompile the monorepo. `composite` emits the `.d.ts` files the other projects consume in place of source.
In large enterprise codebases and monorepos, compiling all source files as a single monolithic program slows down build times. Project References allow you to structure TypeScript code into independent, interlinked modules.
To allow a project to be referenced by another tsconfig.json, enable "composite": true in the child project's configuration:
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"rootDir": "src",
"outDir": "dist"
}
}
Reference child projects in the root or consuming app tsconfig.json:
// apps/web/tsconfig.json
{
"compilerOptions": {
"target": "ES2022"
},
"references": [
{ "path": "../../packages/core" }
]
}
tsc -b)Use TypeScript's build mode (tsc -b) to compile referenced projects incrementally:
# Build referenced projects incrementally in correct dependency order!
tsc -b apps/web
.d.ts outputs have not changed.declaration: true to generate build declaration maps for consumer projects.Congratulations! You have completed all 30 foundational TypeScript Learning Bytes, mastering everything from primitive type annotations to generics, conditional types, custom utility types, and enterprise monorepo compilation!
TypeScript erases entirely at build time, so a `string` annotation produces no runtime check whatsoever. A value arriving from an API is whatever the server actually sent, regardless of what the annotation claims.
`let x = "GET"` infers `string` because the binding can change; `const x = "GET"` infers the literal `"GET"`. That widening rule is why object properties need `as const` to stay narrow.
`string[]` is any number of strings; `[string, number]` is exactly two, in that order. `readonly` removes the mutating methods at compile time, so `push` becomes a type error rather than a runtime surprise.