Skip to main content
← All Articles Β· Β· 10 min read

TypeScript 5.5 New Features: Complete Guide for Developers 2026

Everything you need to know about TypeScript 5.5: inferred type predicates, isolated declarations, JSDoc @import tag, new Set methods, and performance improvements. With practical code examples.

typescriptjavascripttype-systemfrontenddeveloper-toolsprogramming

TypeScript 5.5 arrived as one of the most developer-quality-of-life releases in recent memory. It did not reinvent the type system, but it closed long-standing gaps that caused friction in real codebases β€” from type predicates that required manual annotation to regular expressions that silently accepted invalid syntax. This guide walks through every major feature with working code examples so you can evaluate what to adopt immediately and what to keep in mind for future refactors.

Inferred Type Predicates

Before TypeScript 5.5, narrowing a type inside a filter callback required you to write an explicit type predicate function. If you forgot, TypeScript would widen the inferred return type and your array would remain typed as the union.

Before 5.5 β€” manual annotation required:

type User = { id: number; name: string };
type MaybeUser = User | null;

const users: MaybeUser[] = [
  { id: 1, name: "Alice" },
  null,
  { id: 2, name: "Bob" },
];

// Without the explicit predicate, result is (User | null)[]
function isUser(value: MaybeUser): value is User {
  return value !== null;
}

const validUsers = users.filter(isUser); // User[]

With TypeScript 5.5 β€” inference handles it:

// TypeScript now infers the type predicate from the return expression
const validUsers = users.filter((u) => u !== null); // User[]

The compiler analyses the return expression of functions with a boolean return type. When it can determine that returning true implies a type narrowing, it automatically assigns a type predicate. This works for inline arrow functions and named functions alike.

Practical takeaway: Most .filter(Boolean) and .filter(x => x !== null) patterns will now return correctly narrowed arrays without any helper functions. Audit existing code for unnecessary predicate wrappers β€” many can be deleted.

Control Flow Narrowing for Constant Indexed Accesses

TypeScript has narrowed variables for years, but object property accesses β€” especially those using a runtime key β€” resisted narrowing because the key itself could change between the check and the use.

TypeScript 5.5 narrows obj[key] expressions when key is a const variable (or effectively constant within the block), meaning its value cannot be reassigned between the check and the access.

Before 5.5:

function processRecord(record: Record<string, string | number>, key: string) {
  if (typeof record[key] === "string") {
    // Error: record[key] is still string | number here
    console.log(record[key].toUpperCase()); // type error
  }
}

With TypeScript 5.5:

function processRecord(record: Record<string, string | number>, key: string) {
  if (typeof record[key] === "string") {
    // key is not reassigned, so TypeScript narrows record[key] to string
    console.log(record[key].toUpperCase()); // works
  }
}

The narrowing applies within the same scope as long as TypeScript can prove key was not mutated between the guard and the use. This extends naturally to discriminated union patterns accessed via a computed key.

Practical takeaway: Code that previously required casting (record[key] as string) or destructuring into a local variable can now rely on direct narrowing. This is especially useful in generic utility functions that iterate over object keys.

JSDoc @import Tag

TypeScript’s JSDoc support lets JavaScript projects benefit from type checking without converting to .ts files. The persistent limitation was that importing types in JSDoc required either a full import() expression inside the annotation or a top-level import statement that would be included in the emitted JavaScript.

TypeScript 5.5 introduces the @import JSDoc tag, mirroring the TypeScript import type syntax. The import is purely for tooling; it does not appear in runtime output.

Before 5.5:

// Option A: pollutes runtime with an import
import { SomeType } from "./types.js"; // emitted to JS

/** @param {SomeType} config */
function setup(config) {}

// Option B: verbose inline import
/** @param {import('./types.js').SomeType} config */
function setup(config) {}

With TypeScript 5.5:

// @import { SomeType } from "./types.js"

/** @param {SomeType} config */
function setup(config) {
  // TypeScript resolves SomeType from the @import
}

The @import tag is placed at the top of the file (or anywhere before first use) and follows the same module specifier rules as TypeScript imports. Multiple named imports work on one line.

Practical takeaway: JavaScript projects that rely on JSDoc for type checking β€” common in monorepos that have not migrated to TypeScript β€” can now write cleaner type annotations. The change also reduces the risk of accidentally shipping type-only imports in output bundles.

Regular Expression Syntax Checking

TypeScript has accepted RegExp literals since its beginning, but it treated the pattern string as opaque β€” any invalid syntax was a runtime surprise, not a compile-time error.

TypeScript 5.5 parses regular expression literals and reports syntax errors inline.

Errors TypeScript 5.5 now catches:

// Unterminated character class
const bad1 = /[a-z/; // Error: Unterminated character class.

// Invalid escape sequence
const bad2 = /\p{Letter}/; // Error: if ES target doesn't support Unicode properties

// Invalid backreference
const bad3 = /(\d)\2/; // Error: if group 2 doesn't exist

// Invalid quantifier combination
const bad4 = /a{3,1}/; // Error: numbers out of order in quantifier

// Correct usage
const good = /^[\w.-]+@[\w.-]+\.[a-z]{2,}$/i;

The checking is target-aware. Features like Unicode property escapes (\p{...}) are only valid when the compiler target supports them, so TypeScript will warn if the regex uses a construct incompatible with the configured target.

Practical takeaway: Regex bugs that previously only surfaced at runtime (or only in testing) are now caught during compilation. This is particularly valuable for long-lived utility files where a regex might not be exercised by every test run.

New Set Methods

The ECMAScript Set object has carried a minimal API for years. The 2024 specification added a suite of set-theoretic operations, and TypeScript 5.5 ships type definitions for all of them.

The new methods are:

  • Set.prototype.union(other) β€” elements in either set
  • Set.prototype.intersection(other) β€” elements in both sets
  • Set.prototype.difference(other) β€” elements in this set but not the other
  • Set.prototype.symmetricDifference(other) β€” elements in exactly one of the two sets
  • Set.prototype.isSubsetOf(other) β€” boolean, whether all elements of this set appear in other
  • Set.prototype.isSupersetOf(other) β€” boolean, whether other is a subset of this set
  • Set.prototype.isDisjointFrom(other) β€” boolean, whether the sets share no elements

Usage examples:

const frontend = new Set(["react", "vue", "svelte", "angular"]);
const backend = new Set(["express", "fastify", "nestjs", "react"]);

// Union β€” all tools mentioned in either category
const allTools = frontend.union(backend);
// Set { 'react', 'vue', 'svelte', 'angular', 'express', 'fastify', 'nestjs' }

// Intersection β€” tools appearing in both
const shared = frontend.intersection(backend);
// Set { 'react' }

// Difference β€” frontend-only tools
const frontendOnly = frontend.difference(backend);
// Set { 'vue', 'svelte', 'angular' }

// Symmetric difference β€” tools in exactly one category
const exclusive = frontend.symmetricDifference(backend);
// Set { 'vue', 'svelte', 'angular', 'express', 'fastify', 'nestjs' }

// Subset check
const smallSet = new Set(["react"]);
console.log(smallSet.isSubsetOf(frontend)); // true

// Disjoint check
const dbTools = new Set(["postgres", "redis", "mongodb"]);
console.log(frontend.isDisjointFrom(dbTools)); // true

Each method returns a new Set rather than mutating either operand, making them safe for functional pipelines.

Practical takeaway: Before these methods, developers wrote ad-hoc helpers or reached for lodash. The built-in implementations are faster and require no dependency. Update your tsconfig.json lib to include "ES2024" or later to get the type definitions.

Isolated Declarations

The --isolatedDeclarations flag is the most architecturally significant addition in TypeScript 5.5. It is aimed at large-scale codebases and monorepos that run parallel type checking or use alternative build tools like esbuild, swc, or Rolldown.

The flag enforces that every exported symbol has an explicit type annotation sufficient for a tool to generate .d.ts files without performing full type inference across the entire project graph. When enabled, TypeScript errors on any export whose type cannot be determined from that file alone.

Without isolatedDeclarations β€” inferred return types are fine:

// utils.ts
export function add(a: number, b: number) {
  return a + b; // return type inferred as number
}

export const multiplier = (x: number) => x * 2; // return type inferred

With --isolatedDeclarations β€” explicit annotations required:

// utils.ts
export function add(a: number, b: number): number {
  return a + b; // explicit return type required
}

export const multiplier = (x: number): number => x * 2; // explicit required

// Object exports need explicit types too
export const config: { timeout: number; retries: number } = {
  timeout: 3000,
  retries: 3,
};

tsconfig.json setup:

{
  "compilerOptions": {
    "isolatedDeclarations": true,
    "declaration": true,
    "declarationMap": true
  }
}

The payoff is that build tools can generate .d.ts files for each module in parallel without needing to resolve the full type graph. In a monorepo with hundreds of packages, this can reduce declaration emit time from minutes to seconds.

Practical takeaway: Enable isolatedDeclarations gradually. TypeScript will surface every export missing an explicit annotation. Treat the errors as a migration checklist. The discipline of explicit return types is generally considered good practice anyway, so the enforcement cost is low relative to the build speed gains.

Performance Improvements

TypeScript 5.5 ships internal changes that reduce both compilation time and memory usage, particularly for projects with deep conditional types and large union types.

Key improvements:

  • Faster type instantiation caching. The compiler caches more intermediate results during generic instantiation, reducing redundant work on repeated type patterns.
  • Reduced peak memory. Changes to how the type checker retains intermediate nodes lower the heap ceiling for large projects. Projects with many .d.ts files from node_modules see the most benefit.
  • Faster --watch mode. Incremental rebuilds are more precise about which files need re-checking after a change, reducing unnecessary work in language server scenarios.

Benchmarks from the TypeScript team (approximate figures):

MetricTypeScript 5.4TypeScript 5.5Improvement
Type check time (large project)42s34s~19% faster
Memory peak (large project)2.1 GB1.7 GB~19% reduction
Incremental rebuild (watch)8s5s~38% faster

Results vary by codebase. Projects with heavy use of mapped types and conditional types benefit the most.

Practical takeaway: Upgrade to 5.5 for performance gains alone if your CI type check step takes more than 30 seconds. No configuration changes required β€” the improvements are internal.

Editor and Language Service Improvements

TypeScript 5.5 brings several editor improvements surfaced through the Language Server Protocol, which means they work in VS Code, Neovim with tsserver, WebStorm, and any other LSP-aware editor.

Go-to-definition for string literal types

When a function parameter is typed as a string literal union, β€œGo to Definition” on a call site now navigates to the specific union member matching the passed string, rather than jumping to the entire type declaration. This reduces friction when tracing where a specific variant is defined or used.

type Theme = "light" | "dark" | "system";

function applyTheme(theme: Theme) { /* ... */ }

applyTheme("dark"); // Cmd+click on "dark" now jumps to the "dark" member in Theme

Smarter auto-imports for type-only imports

The language service now automatically uses import type when the imported binding is only used in type positions. Previously, it would emit a regular import and rely on isolatedModules or verbatimModuleSyntax errors to prompt a correction.

// Before: editor generated
import { SomeInterface } from "./types";

// After: editor now generates
import type { SomeInterface } from "./types";

Region-based diagnostics

For very large files, TypeScript 5.5 can report diagnostics for the region of the file visible in the editor before finishing the full-file check. This means errors appear in the viewport faster during editing, improving the perceived responsiveness of the language server.

Practical takeaway: These improvements are automatic. Ensure your editor extension (such as the VS Code TypeScript extension) is using the workspace version of TypeScript rather than the bundled version to pick up the 5.5 language service.

Feature Summary

FeatureImpactConfig Required
Inferred type predicatesRemoves boilerplate in filter/guard patternsNone
Constant indexed access narrowingReduces casting in generic utilitiesNone
JSDoc @import tagCleaner type-only imports in JS filesNone
Regex syntax checkingCatches invalid patterns at compile timeNone
New Set methodsSet algebra without utility librarieslib: ES2024+
Isolated declarationsParallel declaration emit, faster monorepo buildsisolatedDeclarations: true
Performance improvementsFaster type check, lower memoryNone
Editor improvementsFaster diagnostics, smarter importsUse workspace TS version

Upgrading to TypeScript 5.5

The upgrade path is straightforward for most projects:

npm install [email protected] --save-dev
# or
pnpm add -D [email protected]

Run tsc --noEmit after upgrading to surface any new errors. The regex syntax checking is the most likely source of unexpected errors if your codebase contains invalid patterns that were previously ignored. Review each flagged regex β€” some may be genuine bugs, others may need the u or v flag to be valid.

For isolatedDeclarations, treat it as an opt-in migration. Enable it in a single package first, resolve the annotation errors, then expand. The TypeScript team provides a codemod in the 5.5 release notes to add missing return type annotations automatically.

TypeScript 5.5 is a refinement release that rewards developers who care about code correctness and build performance. The inferred type predicates alone will remove dozens of lines of boilerplate in typical codebases, and the isolated declarations flag opens the door to significantly faster toolchains in large projects. The upgrade is low-risk and high-return.

Free Download

50 CLI Commands That Save Hours Every Week

The exact Git shortcuts, file search tricks, Docker commands, and productivity hacks that senior developers use daily. Compiled from 5+ years of shipping production code.

  • Git mastery (10 cmds)
  • File & search wizardry
  • Docker & DevOps tricks
  • Process & network tools
  • Productivity boosters
  • macOS & Linux install guide

No spam. 1 email/week max. Unsubscribe anytime.

Found this guide useful? Check out our free developer tools.