Skip to content

TypeScript 6.0: 3 Breaking Changes That Hit My NestJS Project

Published: 2026-06-27

Dependabot opened a dev-tooling upgrade PR: TypeScript 5.9.3 β†’ 6.0.3, ESLint 9 β†’ 10. I merged it. The ESLint changes were minor. Then I ran pnpm build.

This post covers three compiler errors from that upgrade β€” the ones that came from how the project was configured and how NestJS initializes class properties outside the constructor. In the order I hit them.


TS5011 β€” rootDir Is No Longer Inferred

In TypeScript 5, rootDir was inferred automatically from the common source directory of all input files. TypeScript 6 changed the default to . β€” the directory containing tsconfig.json β€” and now requires it to be set explicitly.1

The NestJS scaffold’s tsconfig.json has no explicit rootDir β€” though outDir is set, which is why the missing rootDir surfaces on upgrade:

{
  "compilerOptions": {
    "outDir": "./dist"
  }
}

The obvious fix is to add "rootDir": "./src" to tsconfig.json. Don’t.

If you add it there, the compiler immediately throws a second error:

error TS6059: File 'test/app.e2e-spec.ts' is not under 'rootDir' './src'.
  'rootDir' is expected to contain all source files.

NestJS’s default tsconfig.json has no include or exclude β€” it picks up everything in the project, including test/. Setting rootDir: "./src" while test/ is still in scope is a contradiction.

The correct fix is to add rootDir only to tsconfig.build.json, which already excludes test/:

// tsconfig.build.json β€” before
{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
// tsconfig.build.json β€” after
{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"],
  "compilerOptions": {
    "rootDir": "./src"
  }
}

tsconfig.build.json is what nest build uses. Since test/ is already excluded there, rootDir: "./src" is valid. The base tsconfig.json β€” used by your IDE and ts-jest β€” stays unchanged.


TS5101 β€” baseUrl Promoted to Error

baseUrl was fully supported in TypeScript 5 with no warnings. TypeScript 6.0 deprecated it and enforces the deprecation immediately as a compile error.2

error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0.
  Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.

The NestJS scaffold includes baseUrl in tsconfig.json β€” a common path-resolution setting that was previously harmless:

{
  "compilerOptions": {
    "baseUrl": "./"
  }
}

The right long-term fix is to migrate to path aliases using only paths β€” baseUrl is being removed as a module lookup root, and paths entries work without it. But that’s a larger refactor.

The practical short-term fix, and the one the error message recommends:

{
  "compilerOptions": {
    "baseUrl": "./",
    "ignoreDeprecations": "6.0"
  }
}

This silences the error and buys time until TypeScript 7. Add it to tsconfig.json β€” it applies to all extends, including tsconfig.build.json.


TS2564 β€” strictPropertyInitialization Now On by Default

strictPropertyInitialization is part of strict mode and was off by default in TypeScript 5 unless strict: true was set. TypeScript 6 made strict: true the default, which activates it β€” along with every other strict flag β€” for projects that hadn’t opted in before.3

error TS2564: Property 'ws' has no initializer and is not definitely assigned in the constructor.
error TS2564: Property 'server' has no initializer and is not definitely assigned in the constructor.
error TS2564: Property 'workerUtils' has no initializer and is not definitely assigned in the constructor.

All three of these properties follow the same NestJS pattern: they are declared on the class but initialized outside the constructor β€” either in a lifecycle hook or via a decorator.

// FinnhubService β€” initialized in onModuleInit()
@Injectable()
export class FinnhubService implements OnModuleInit {
  private ws: WebSocket; // TS2564

  onModuleInit() {
    this.ws = new WebSocket('wss://ws.finnhub.io?token=...');
  }
}
// PricesGateway β€” injected by the @WebSocketServer() decorator
@WebSocketGateway()
export class PricesGateway {
  @WebSocketServer()
  server: Server; // TS2564
}
// QueueService β€” initialized asynchronously in onModuleInit()
@Injectable()
export class QueueService implements OnModuleInit {
  private workerUtils: WorkerUtils; // TS2564

  async onModuleInit() {
    this.workerUtils = await makeWorkerUtils({ connectionString: process.env.DATABASE_URL });
  }
}

TypeScript can’t verify that these properties are set before use β€” the initialization happens in framework-controlled lifecycle methods, not the constructor. The fix is the definite assignment assertion !, which tells the compiler you are taking responsibility:

private ws!: WebSocket;
server!: Server;
private workerUtils!: WorkerUtils;

Before adding ! to every flagged property, verify the property actually is initialized before first use. The NestJS lifecycle guarantees onModuleInit() runs before the module handles any requests, and @WebSocketServer() is populated before the gateway handles events. These three are safe.

A genuinely uninitialized property would be a real bug β€” the ! would just hide it.


Upgrade Order

If you hit all three errors at once, apply them in this order:

  1. tsconfig.build.json β€” add rootDir. Eliminates TS5011.
  2. tsconfig.json β€” add ignoreDeprecations. Eliminates TS5101.
  3. Class properties β€” add ! case by case. Eliminates TS2564.

Confirm the build passes after steps 1 and 2 before touching class properties. If more errors surface after adding rootDir, they were hidden by the missing rootDir and are genuine issues worth addressing separately.


Summary

Error TypeScript 5 TypeScript 6 Fix
TS5011 rootDir inferred automatically rootDir must be explicit Add to tsconfig.build.json only
TS5101 baseUrl: fully supported baseUrl: compile error "ignoreDeprecations": "6.0"
TS2564 strictPropertyInitialization off on by default ! assertion on lifecycle-owned properties

Further Reading

Footnotes

  1. TypeScript 6.0 release notes β€” rootDir now defaults to the tsconfig directory. Previously inferred from the common source directory; now always defaults to the tsconfig.json directory. ↩

  2. TypeScript 6.0 release notes β€” Deprecated: –baseUrl. baseUrl is deprecated in TS6 and immediately enforces as a compile error; ignoreDeprecations: "6.0" silences it. ↩

  3. TypeScript 6.0 release notes β€” Simple Default Changes. strict now defaults to true, which activates strictPropertyInitialization and all other strict-mode flags. ↩