| |

TypeScript 97 ๐Ÿ”ท Migrating Between TypeScript Versions

TypeScript releases a new minor version roughly every three months. Most of these releases are additive โ€” new syntax, new type features, new compiler options. But some releases introduce breaking changes: behavior that compiled and ran correctly in one version produces a different result in the next. The major version boundaries (4.0, 5.0, 6.0) tend to concentrate the breaking changes, but minor versions can also deprecate APIs, tighten inference, or change default settings.

Migrating between TypeScript versions is not the same problem as migrating from JavaScript. The codebase already has types. The risk is that those types were correct under one compiler and are wrong under another. A project that upgrades from TypeScript 4.9 to 5.9 in one step may hit hundreds of new errors โ€” not because the code became worse, but because the compiler became stricter, the type inference changed, or a library’s type definitions assume a newer compiler feature.

The LFCA and Angular chapters in this series focus on runtime behavior and application structure. This chapter sits at the tooling layer: the compiler, the type definitions, and the CI pipeline that keeps them synchronized.

Key point: TypeScript does not follow semantic versioning in the strictest sense. Minor versions can introduce breaking changes. The TypeScript team publishes release notes for every version, and the “Breaking Changes” section is the one to read before upgrading. The recommended approach is to upgrade one minor version at a time, run tsc --noEmit after each, and fix the errors before moving to the next version .


Why TypeScript version migration matters

TypeScript is a compiler. The version of the compiler determines what types are accepted, what types are inferred, and what errors are reported. A codebase that is type-correct under one version may not be under another. The version of the compiler is not a detail โ€” it is part of the codebase’s contract.

The inference drift problem. TypeScript’s type inference improves over time. A function that returned a widened type in 4.x may return a narrower type in 5.x. A variable that was implicitly any in one version may be unknown in another. These changes are improvements, but they surface as errors in code that depended on the old behavior. The migration is the process of updating the code to work with the improved inference.

The library types problem. The @types/* packages for libraries are maintained separately from TypeScript itself. A new version of @types/react may require a newer TypeScript version. If the codebase pins TypeScript to an older version, installing the latest @types/react can produce errors that are not the code’s fault. The versions of TypeScript, the type definitions, and the libraries must be compatible.

The compiler option problem. TypeScript occasionally changes the default value of a compiler option or deprecates an option entirely. A project that relies on a default from an older version may find the default changed in a newer version. The tsconfig.json must be updated to match the new defaults or to explicitly set the old behavior.

The tooling problem. ESLint, Jest, Vite, and other tools embed or depend on specific TypeScript versions. A TypeScript upgrade may require upgrading the tooling in lockstep. The typescript-eslint package, for example, declares a supported TypeScript version range. Upgrading TypeScript beyond that range produces warnings and may break lint rules.

The trade-off. Upgrading is not optional forever. Older TypeScript versions stop receiving bug fixes and security patches. Library type definitions eventually require newer compiler features. The choice is when to upgrade, not whether. The recommended cadence is to upgrade one minor version at a time and to keep the codebase within one or two minor versions of the latest release.


a. The Upgrade Process

The upgrade process has five phases: read the release notes, upgrade one version, run the type checker, fix the errors, and repeat.

Read the release notes. Every TypeScript release has a blog post with a “Breaking Changes” section. The TypeScript wiki on GitHub has a page for each version that lists the breaking changes in detail. Reading these before upgrading tells the team what to expect and how many changes are likely.

The typical breaking changes fall into a few categories:

Tighter inference. A type that was inferred as any may now be inferred as unknown. A union that was inferred as string may now be inferred as string | undefined. The fix is to add explicit annotations where the inferred type is not what the code needs.

Deprecated APIs. TypeScript’s own compiler APIs (ts.createProgram, ts.SourceFile, etc.) occasionally deprecate functions. This affects tools that build on TypeScript, not application code. For application code, the deprecated items are usually compiler flags or syntax that was never fully supported.

Changed defaults. The default value of a compiler option changes. The most significant example is the types field in tsconfig.json, which began defaulting to an empty array in TypeScript 6.0 . This means @types/* packages are no longer automatically included; they must be listed explicitly in the types field.

Stricter checks. A rule that was previously a warning becomes an error, or a new check is added that catches code that was previously accepted. The strict option’s bundle grows over time. Code that compiled with strict: true in 4.x may have new errors in 5.x.

Upgrade one version. The npm install typescript@5.4 command installs a specific version. The upgrade should be one minor version at a time. Upgrading from 4.9 to 5.9 in one step accumulates the breaking changes of ten releases. Upgrading from 5.3 to 5.4 isolates the changes of one release.

Run the type checker. The npx tsc --noEmit command runs the compiler in check-only mode. The output is the list of errors introduced by the new version. The team fixes these errors before the next upgrade.

Fix the errors. The errors fall into a small number of categories. Each has a standard fix:

  • Implicit any: add a type annotation or use unknown.
  • Narrowed type: add a type guard or a type assertion.
  • Changed API: update the call to the new API.
  • Deprecated option: remove the option or replace it with the new one.
  • Missing types entry: add the @types/* package to the types array.

Repeat. After the errors are fixed and the new version compiles cleanly, the next minor version can be installed. The whole process can take hours or days, depending on the size of the codebase and the number of breaking changes.


b. Common Breaking Changes by Version

The breaking changes that affect application code most often are the ones that tighten inference and change defaults. A few examples from recent versions illustrate the pattern.

TypeScript 4.x โ†’ 5.0. The moduleResolution: "bundler" option was introduced. The verbatimModuleSyntax option was added. Type parameter defaults changed in some cases. The --target ES3 support was deprecated.

TypeScript 5.x โ†’ 5.5. Inferred type predicates were added, which improved type narrowing in some functions but could change the inferred type of others. The isolatedDeclarations option was introduced. Control flow narrowing was tightened.

TypeScript 5.x โ†’ 5.9. The import defer syntax was introduced. The --module node20 option was added. A new check for Uint8Array generic usage was added.

TypeScript 5.x โ†’ 6.0. The types field in tsconfig.json began defaulting to an empty array. This is the most impactful change for projects that relied on automatic inclusion of @types/* packages. Every @types package that the project uses must now be listed explicitly. The moduleResolution: "node" option was deprecated in favor of node10. The esModuleInterop and allowSyntheticDefaultImports behavior was tightened.

The pattern across these versions is consistent: TypeScript gets stricter over time. The code that compiled cleanly under the old version may have new errors under the new version. The errors are not bugs โ€” they are opportunities to make the code more type-safe. The migration is the process of taking advantage of those opportunities.

For each version, the TypeScript wiki has a “Breaking Changes” page. The page for the current version is the first thing to read before upgrading. It lists every change that could break existing code, with examples and the recommended fix.


c. The Tooling Ecosystem

TypeScript does not exist in isolation. The compiler is used by the editor, the linter, the test runner, the bundler, and the type definition packages. Upgrading TypeScript means checking that all of these are compatible with the new version.

The editor. VS Code bundles its own TypeScript version, but it can be configured to use the workspace version. The typescript.tsdk setting in .vscode/settings.json points the editor at the node_modules/typescript/lib directory. This ensures that the editor shows the same errors as the CI pipeline.

The linter. typescript-eslint declares a supported TypeScript version range. Upgrading TypeScript beyond that range produces warnings and may break lint rules. The typescript-eslint release notes document the supported range for each version. The linter is typically upgraded after TypeScript, once the new version is in use.

The test runner. Jest and Vitest use TypeScript through ts-jest, @swc/jest, or Vite’s esbuild. The test runner does not type-check by default โ€” it only transpiles. The type checking is done separately by tsc --noEmit. The test runner’s TypeScript support is usually version-agnostic, but the transpiler’s supported syntax may lag behind the compiler.

The bundler. Vite and esbuild transpile TypeScript without type-checking. Their TypeScript support is version-agnostic in most cases, but new syntax may not be supported until the transpiler is updated. The verbatimModuleSyntax option, for example, requires the bundler to handle type-only imports correctly.

The type definitions. The @types/* packages are published by the DefinitelyTyped community. They declare their supported TypeScript version in package.json. Installing the latest @types/react may require a newer TypeScript version than the project uses. The npm install command warns about the mismatch, but does not prevent it.

The recommended upgrade order is:

  1. Upgrade TypeScript.
  2. Run tsc --noEmit.
  3. Fix the errors.
  4. Upgrade the type definitions.
  5. Upgrade typescript-eslint.
  6. Upgrade the test runner and the bundler if needed.

Each step is a separate commit. Each commit is a checkpoint that can be reverted if something breaks.


Complete Example Session

This session upgrades a project from TypeScript 5.8 to 5.9 and then to 6.0, fixing the errors introduced at each step.

// ============================================
// PART 1: THE STARTING POINT
// ============================================

// package.json
{
  "devDependencies": {
    "typescript": "5.8.0",
    "typescript-eslint": "^8.0.0",
    "@types/node": "^20.0.0"
  }
}

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noEmit": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

// The project compiles with zero errors.

// ============================================
// PART 2: UPGRADE TO TYPESCRIPT 5.9
// ============================================

// npm install --save-dev typescript@5.9

// Run the type checker
npx tsc --noEmit

// Error: Cannot find module 'node:fs' or its corresponding type declarations.
// Cause: TypeScript 5.9 changed the module resolution for node: prefixes.
// Fix: Update @types/node to a version that supports the new behavior.

// npm install --save-dev @types/node@22

// Run again
npx tsc --noEmit

// Error: Type 'Uint8Array<ArrayBufferLike>' is not assignable to
//        type 'Uint8Array<ArrayBuffer>'.
// Cause: TypeScript 5.9 added a generic parameter to Uint8Array.
// Fix: Update the code to use the generic form.

// Before
function readBytes(buffer: Uint8Array): number {
  return buffer.length;
}

// After
function readBytes(buffer: Uint8Array<ArrayBufferLike>): number {
  return buffer.length;
}

// Run again
npx tsc --noEmit

// No errors. The upgrade to 5.9 is complete.

// ============================================
// PART 3: UPGRADE TO TYPESCRIPT 6.0
// ============================================

// npm install --save-dev typescript@6.0

// Run the type checker
npx tsc --noEmit

// Error: Cannot find name 'describe'. Cannot find name 'it'. Cannot find name 'expect'.
// Cause: TypeScript 6.0 changed the default for the `types` field.
//        Previously, all @types/* packages were automatically included.
//        Now the default is an empty array.
// Fix: Add the types explicitly to tsconfig.json.

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noEmit": true,
    "skipLibCheck": true,
    "types": ["node", "vitest/globals"]
  },
  "include": ["src/**/*"]
}

// Run again
npx tsc --noEmit

// Error: Option 'moduleResolution: node' is deprecated. Use 'node10' instead.
// Cause: TypeScript 6.0 deprecated the "node" value.
// Fix: Replace "node" with "node10" or "bundler" depending on the project.

// tsconfig.json (already using "bundler" โ€” no change needed for this project)

// Run again
npx tsc --noEmit

// No errors. The upgrade to 6.0 is complete.

// ============================================
// PART 4: UPGRADE THE LINTER
// ============================================

// npm install --save-dev typescript-eslint@latest

// Check the compatibility
npx eslint .

// If the linter reports a version mismatch, check the typescript-eslint
// release notes for the supported TypeScript version range.
// The linter is usually upgraded after TypeScript.

// ============================================
// PART 5: UPDATE THE EDITOR
// ============================================

// .vscode/settings.json
{
  "typescript.tsdk": "node_modules/typescript/lib"
}

// This tells VS Code to use the workspace TypeScript version
// instead of the version bundled with the editor.

// ============================================
// PART 6: THE CI PIPELINE
// ============================================

// .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm run typecheck
      - run: npm run lint
      - run: npm run test

// The typecheck step runs tsc --noEmit with the upgraded version.

// ============================================
// PART 7: THE DEPRECATED OPTIONS CHECK
// ============================================

// Run tsc with the --showConfig flag to see the resolved config
npx tsc --showConfig

// Look for deprecation warnings in the output.
// Remove or replace any deprecated options.

// ============================================
// PART 8: THE VERSION RANGE IN package.json
// ============================================

// package.json
{
  "devDependencies": {
    "typescript": "~5.9.0"
  }
}

// The ~ (tilde) allows patch updates within the minor version.
// The ^ (caret) allows minor updates within the major version.
// For TypeScript, the recommended range is ~ to control minor upgrades.

// ============================================
// PART 9: THE ROLLBACK PLAN
// ============================================

// Each upgrade is a separate commit.
// If an upgrade introduces errors that cannot be resolved quickly,
// the commit can be reverted.

// git revert <commit-hash>

// The codebase returns to the previous TypeScript version.
// The upgrade can be retried later with more time.

// ============================================
// PART 10: THE UPGRADE CHECKLIST
// ============================================

// 1. Read the release notes for the target version
// 2. Install the new TypeScript version
// 3. Run tsc --noEmit
// 4. Fix the errors
// 5. Upgrade @types/* packages if needed
// 6. Upgrade typescript-eslint
// 7. Update the editor's TypeScript version
// 8. Verify the CI pipeline
// 9. Check for deprecated options
// 10. Commit the upgrade as a separate change

The ten parts cover the starting point, the upgrade to 5.9, the upgrade to 6.0, the linter upgrade, the editor configuration, the CI pipeline, the deprecated options check, the version range, the rollback plan, and the upgrade checklist.


Quick Reference

The Upgrade Process

StepCommandPurpose
Installnpm install -D typescript@5.9Upgrade the compiler
Checknpx tsc --noEmitFind new errors
FixEdit source filesResolve errors
Verifynpx tsc --noEmitConfirm zero errors
Commitgit commit -m "Upgrade to TS 5.9"Checkpoint

The Common Breaking Changes

CategoryExampleFix
Tighter inferenceany โ†’ unknownAdd type annotations
Changed defaultstypes defaults to []List types explicitly
New checksUint8Array genericUpdate the type
Deprecated optionsmoduleResolution: nodeUse node10 or bundler
Deprecated APIsCompiler APIsUpdate to the new API

The Tooling Compatibility

ToolChecks TypeScript VersionUpgrade Order
typescript-eslintYesAfter TypeScript
@types/*YesAfter TypeScript
VS CodeConfigurableSame as workspace
Vitest / JestNoIndependently
Vite / esbuildNoIndependently

The tsconfig Changes by Version

VersionChangeAction
5.0moduleResolution: bundler addedOptional
5.9Uint8Array genericUpdate types
6.0types defaults to []List types explicitly
6.0moduleResolution: node deprecatedUse node10 or bundler

Best Practices

โœ… Do This:

# Upgrade one minor version at a time
npm install --save-dev typescript@5.9                     # โœ…
# Run the type checker after every upgrade
npx tsc --noEmit                                           # โœ…
# Read the release notes before upgrading
# The "Breaking Changes" section is the one to read.        # โœ…
// Pin the TypeScript version with a tilde
{ "typescript": "~5.9.0" }                                // โœ…
// Set the editor to use the workspace TypeScript
{ "typescript.tsdk": "node_modules/typescript/lib" }      // โœ…

โŒ Don’t Do This:

# Don't upgrade across multiple major versions at once
npm install --save-dev typescript@6.0  # from 4.x           # โŒ
// Don't use a caret range for TypeScript
{ "typescript": "^5.0.0" }  // may pull 5.9 unexpectedly    // โŒ
# Don't skip the type check after upgrading
npm install typescript@5.9 && git commit                    # โŒ
// Don't forget to update the types field for 6.0
{ "compilerOptions": { "strict": true } }  // no "types"     // โŒ

Common Pitfalls

PitfallWhy It HappensFix
Hundreds of errorsUpgraded too far in one stepUpgrade one minor version at a time
Linter breakstypescript-eslint version mismatchUpgrade the linter after TypeScript
Editor shows different errorsEditor uses bundled TypeScriptSet typescript.tsdk
@types mismatchInstalled latest @types/*Match to the TypeScript version
CI failsCI uses an older TypeScriptUpdate package.json and lock file
Missing globals in 6.0types defaults to []Add "types": ["node"]

Real-World Examples

1. Upgrade One Version

npm install --save-dev typescript@5.9
npx tsc --noEmit

2. Fix a Narrowed Type

// Before: implicit any
function parse(data) { return data.value; }

// After: explicit unknown
function parse(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String((data as { value: unknown }).value);
  }
  throw new Error('Invalid data');
}

3. Update the types Field

{ "compilerOptions": { "types": ["node", "vitest/globals"] } }

4. Deprecated moduleResolution

// Before
{ "moduleResolution": "node" }

// After
{ "moduleResolution": "bundler" }

5. Update @types/node

npm install --save-dev @types/node@22

6. Update typescript-eslint

npm install --save-dev typescript-eslint@latest

7. Editor Configuration

{ "typescript.tsdk": "node_modules/typescript/lib" }

8. CI Step

- run: npm run typecheck

9. Pin the Version

{ "typescript": "~5.9.0" }

10. Rollback

git revert <commit-hash>

Visual

The Upgrade Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  UPGRADE FLOW                                โ”‚
โ”‚                                              โ”‚
โ”‚  Read release notes                          โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  npm install typescript@5.9                  โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  npx tsc --noEmit                            โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”œโ”€ 0 errors โ†’ commit and repeat        โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ””โ”€ errors โ†’ fix                        โ”‚
โ”‚              โ”‚                               โ”‚
โ”‚              โ–ผ                               โ”‚
โ”‚           npx tsc --noEmit  โ†’ 0 errors       โ”‚
โ”‚              โ”‚                               โ”‚
โ”‚              โ–ผ                               โ”‚
โ”‚           commit and repeat                  โ”‚
โ”‚                                              โ”‚
โ”‚  Each minor version is a separate checkpoint.โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Breaking Change Categories

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  BREAKING CHANGE CATEGORIES                  โ”‚
โ”‚                                              โ”‚
โ”‚  Tighter inference:                          โ”‚
โ”‚    any โ†’ unknown                             โ”‚
โ”‚    string โ†’ string | undefined               โ”‚
โ”‚    Fix: add annotations                      โ”‚
โ”‚                                              โ”‚
โ”‚  Changed defaults:                           โ”‚
โ”‚    types now defaults to []                  โ”‚
โ”‚    Fix: list types explicitly                โ”‚
โ”‚                                              โ”‚
โ”‚  Deprecated options:                         โ”‚
โ”‚    moduleResolution: node โ†’ node10           โ”‚
โ”‚    Fix: use the new value                    โ”‚
โ”‚                                              โ”‚
โ”‚  Stricter checks:                            โ”‚
โ”‚    new rules catch old code                  โ”‚
โ”‚    Fix: update the code                      โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Tooling Upgrade Order

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  TOOLING UPGRADE ORDER                       โ”‚
โ”‚                                              โ”‚
โ”‚  1. TypeScript                               โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  2. @types/* packages                        โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  3. typescript-eslint                        โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  4. Editor (tsdk setting)                    โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  5. Test runner / bundler (if needed)        โ”‚
โ”‚                                              โ”‚
โ”‚  Each step is a separate commit.             โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The CI Pipeline

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CI PIPELINE                                 โ”‚
โ”‚                                              โ”‚
โ”‚  Push / PR                                   โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  npm ci                                      โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  tsc --noEmit โ”€โ”€> type errors?               โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”œโ”€ YES โ†’ block merge                   โ”‚
โ”‚       โ””โ”€ NO  โ†’ continue                      โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  eslint .  โ”€โ”€> lint errors?                  โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”œโ”€ YES โ†’ block merge                   โ”‚
โ”‚       โ””โ”€ NO  โ†’ continue                      โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  vitest run โ”€โ”€> test failures?               โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”œโ”€ YES โ†’ block merge                   โ”‚
โ”‚       โ””โ”€ NO  โ†’ merge allowed                 โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Upgrade cadenceOne minor version at a time
Release notesThe “Breaking Changes” section
Type checkernpx tsc --noEmit after each upgrade
Common changeTighter inference (any โ†’ unknown)
Common changetypes defaults to [] in 6.0
Common changemoduleResolution: node deprecated in 6.0
Tooling orderTypeScript โ†’ @types โ†’ typescript-eslint
Editor configtypescript.tsdk in VS Code settings
Version pin~5.9.0 (tilde, not caret)
Rollbackgit revert the upgrade commit

Key takeaways:

  • TypeScript minor versions can introduce breaking changes. The compiler gets stricter over time. Code that compiled cleanly under one version may have new errors under the next. The release notes’ “Breaking Changes” section is the source of truth for what changed.
  • Upgrade one minor version at a time. Jumping from 4.9 to 6.0 accumulates the breaking changes of a dozen releases. Upgrading one version at a time isolates the changes and makes the errors manageable.
  • Run tsc --noEmit after every upgrade. The type checker is the tool that reports the errors introduced by the new version. The fix for each error is a small change to the code or the configuration.
  • The common breaking changes are inference tightening, default changes, and deprecated options. TypeScript 6.0 changed the default for the types field to an empty array, which requires every @types package to be listed explicitly. TypeScript 6.0 also deprecated moduleResolution: node in favor of node10 or bundler.
  • Upgrade the tooling after TypeScript. The @types/* packages and typescript-eslint declare their supported TypeScript version ranges. Upgrading them before TypeScript produces warnings. The recommended order is TypeScript, then @types, then the linter, then the editor, then the test runner and bundler.
  • Set the editor to use the workspace TypeScript. The typescript.tsdk setting in .vscode/settings.json ensures that the editor shows the same errors as the CI pipeline. Without it, the editor may use a bundled version of TypeScript that is different from the project’s.
  • Pin the TypeScript version with a tilde. The ~5.9.0 range allows patch updates within the minor version. The ^5.9.0 range allows minor updates that may introduce breaking changes. TypeScript is not a library where caret ranges are appropriate.

Remember: Migrating between TypeScript versions is not a single event. It is a process that happens every few months when a new version is released. The process is: read the release notes, upgrade one version, run the type checker, fix the errors, upgrade the tooling, and commit. Each upgrade is a checkpoint that can be reverted if something breaks. The compiler gets stricter over time, and the codebase gets safer with it. The migration is the price of the improvements.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!