The TypeScript 5.x series has introduced many features that strengthen the type system and improve the developer experience. This article highlights the ones most useful in everyday coding.
Const Type Parameters (5.0)
Adding a const modifier to a function’s type parameter preserves literal types when passing values through.
function getConfig<T extends readonly string[]>(keys: T): T {
return keys
}
// Before: inferred as string[]
const config1 = getConfig(['dev', 'staging', 'prod'])
// With const type parameter: inferred as a tuple of literals
const config2 = getConfig<const>(['dev', 'staging', 'prod'])
// type: readonly ["dev", "staging", "prod"]
This is handy when you want object properties to keep their literal types. No need to write as const at the call site — the code stays clean.
Stabilized Decorators (5.0)
Starting with TypeScript 5.0, Stage 3 ECMAScript decorators are natively supported. Unlike the experimental decorators, you no longer need experimentalDecorators enabled in your compiler options.
function log(target: any, context: ClassMethodDecoratorContext) {
const methodName = String(context.name)
return function (this: any, ...args: any[]) {
console.log(`${methodName} called with`, args)
return target.call(this, ...args)
}
}
class Calculator {
@log
add(a: number, b: number) {
return a + b
}
}
Developers coming from Angular or NestJS will find the syntax familiar, but note the changes — it now follows the official ECMAScript spec.
The satisfies Operator (4.9 / 5.x)
satisfies lets you check that a value conforms to a type while keeping its inferred narrow type.
type Color = 'red' | 'green' | 'blue'
type Palette = Record<string, Color>
const palette = {
primary: 'blue',
secondary: 'green',
// assigning 'yellow' here would trigger an error
} satisfies Palette
// palette.primary is inferred as "blue", not string
With a traditional type annotation (: Palette), the inference would widen to string. satisfies runs type checking without losing the literal inference — a clear win.
Improved Module Resolution (5.x)
TypeScript 5.x adds a bundler option for moduleResolution. It aligns with how modern bundlers like Vite and esbuild resolve modules.
{
"compilerOptions": {
"moduleResolution": "bundler",
"module": "ESNext",
"target": "ES2022"
}
}
This improves compatibility with the modern ecosystem: the exports field in package.json works correctly, and you can import files without the .ts extension.
Practical Template Literal Types
Template literal types were introduced in 4.1, but combining them with union types in 5.x makes them even more powerful.
type Size = 'sm' | 'md' | 'lg'
type Variant = 'primary' | 'secondary'
// "btn-sm-primary" | "btn-sm-secondary" | "btn-md-primary" ...
type ButtonClass = `btn-${Size}-${Variant}`
function getButtonClass(size: Size, variant: Variant): ButtonClass {
return `btn-${size}-${variant}`
}
This is perfect for type-safe UI component class names or API endpoint paths.
Wrapping Up
Every TypeScript 5.x feature moves in the same direction: stronger type safety with less boilerplate. satisfies and const type parameters are especially easy to introduce into existing codebases and deliver immediate value. Make sure to take advantage of these new capabilities when you upgrade.

