tezvyn:

Explain TypeScript Project References in a monorepo and their configuration

AI-drafted, machine-checkedSource: typescriptlang.orgadvanced

This tests monorepo build scaling. Good answers: split into composite projects with references arrays, use tsc --build for incremental compilation, and consume .d.ts outputs for boundaries. Red flag: calling it path mapping or omitting --build.

WHAT THIS TESTS: This question evaluates whether you understand how to scale TypeScript beyond a single tsconfig.json in a large codebase. The interviewer wants to know if you can enforce architectural boundaries, reduce build times, and manage dependency graphs across multiple packages or modules in a monorepo. It is specifically about the project references feature introduced in TypeScript 3.0 and the build mode that accompanies it.

A GOOD ANSWER COVERS: First, the core problem: a single root tsconfig forces every edit to typecheck the entire repo, allows tests to import source in uncontrolled ways, and cannot build disjoint outputs cleanly. Second, the configuration: each sub-project gets its own tsconfig with composite set to true in upstream projects, declaration enabled so .d.ts files are emitted, and a references array pointing to dependent projects by path. Third, the build orchestration: you run tsc --build at the root, which reads the reference graph, skips up-to-date projects, and compiles only what changed. Fourth, the consumption model: downstream projects load the upstream .d.ts declarations instead of re-parsing source, which is the mechanism that delivers speed and enforces separation.

COMMON WRONG ANSWERS: A red flag is suggesting you simply run multiple independent tsc commands or use path aliases to fake modularity. Another mistake is omitting the composite flag or forgetting declaration emit, which breaks the reference contract because downstream projects have no .d.ts files to import. Some candidates also confuse project references with npm workspaces or yarn workspaces; while those manage node_modules, references manage TypeScript compilation graphs and incremental checking.

LIKELY FOLLOW-UPS: The interviewer might ask how you handle circular references, which TypeScript forbids in project references and which you must break by refactoring shared code into a third project. They might also ask about outFile for bundled declarations, how watch mode works with tsc --build --watch, or how this integrates with external build tools like Bazel or Nx. You should also be ready to explain why pre-built .d.ts files are faster than re-typechecking source, touching on the skipLibCheck tradeoff.

ONE CONCRETE EXAMPLE: Imagine a monorepo with a shared utils package and a web app that depends on it. The utils folder contains a tsconfig.json with compilerOptions composite true and declaration true, outputting to a dist folder. The web app folder contains a tsconfig.json with a references array containing path ../utils. When a developer runs tsc --build in the web app folder, TypeScript automatically builds utils first if needed, then loads utils/dist/index.d.ts instead of re-checking utils/src/index.ts. Changing only a web app test file does not trigger a re-check of utils internals, cutting incremental build time from minutes to seconds in large repos.

Read the original → typescriptlang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.