TypeScript continues to evolve with powerful features that make JavaScript development safer and more productive. Let's dive into the most exciting additions in TypeScript 5.x.
1. The satisfies Operator
Finally, we can validate that an expression matches a type without changing the resulting type:
type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;
// Type is preserved!
palette.red.at(0); // Works - TypeScript knows it's a tuple
palette.green.toUpperCase(); // Works - TypeScript knows it's a string2. Decorators (Stage 3)
function logged(originalMethod: any, context: ClassMethodDecoratorContext) {
const methodName = String(context.name);
function replacementMethod(this: any, ...args: any[]) {
console.log(`Calling ${methodName} with`, args);
const result = originalMethod.call(this, ...args);
console.log(`${methodName} returned`, result);
return result;
}
return replacementMethod;
}
class Calculator {
@logged
add(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3);
// Logs: "Calling add with [2, 3]"
// Logs: "add returned 5"3. Const Type Parameters
// Before: loses literal types
function getRoutes<T extends readonly string[]>(routes: T) {
return routes;
}
const r1 = getRoutes(["home", "about"]); // string[]
// After: preserves literal types with const
function getRoutes<const T extends readonly string[]>(routes: T) {
return routes;
}
const r2 = getRoutes(["home", "about"]); // readonly ["home", "about"]4. All Enums Are Now Union Enums
enum Direction {
Up,
Down,
Left,
Right
}
// TypeScript 5+ treats this as a union
// Direction = Direction.Up | Direction.Down | Direction.Left | Direction.Right
function move(dir: Direction) {
// Exhaustiveness checking works perfectly now
switch (dir) {
case Direction.Up: return "Moving up";
case Direction.Down: return "Moving down";
case Direction.Left: return "Moving left";
case Direction.Right: return "Moving right";
}
}5. Module Resolution Bundler Mode
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "bundler",
// Combines the best of node and classic resolution
// Supports package.json exports
// Supports relative imports without extensions
}
}6. Switch(true) Narrowing
function processValue(value: string | number | boolean) {
switch (true) {
case typeof value === "string":
// TypeScript narrows to string here
console.log(value.toUpperCase());
break;
case typeof value === "number":
// Narrows to number
console.log(value.toFixed(2));
break;
default:
// Narrows to boolean
console.log(value ? "yes" : "no");
}
}Migration Tips
- Update incrementally - TypeScript 5.x is mostly backward compatible
- Enable
verbatimModuleSyntaxfor cleaner imports - Replace legacy decorators with Stage 3 decorators gradually
- Use
satisfiesinstead of type assertions where possible - Enable
moduleResolution: "bundler"for modern projects
No comments yet. Be the first!