Typescript 2023: The Year in Review
TypeScript continues to evolve with significant improvements in type safety and developer experience. Let’s explore the key features that landed this year and how they improve our codebases.
Decorators
After years of experimental status, decorators finally landed as a stable feature in TypeScript 5.0. This implementation aligns with the Stage 3 Decorator Proposal, the ECMAScript specification, and is thoroughly documented in the TypeScript Handbook.
function logged(value: any, context: DecoratorContext) {
if (context.kind === "method") {
return function (...args: any[]) {
console.log(`Calling ${context.name}`);
return value.call(this, ...args);
};
}
}
class API {
@logged
getData() {
return fetch("/api/data");
}
}
This stable implementation resolves years of uncertainty around decorator syntax and provides a standardized way to add metadata and behavior to classes and their members.
Resource Management with using
The using
declaration implements the TC39 Explicit Resource Management proposal, specified in the ECMAScript draft, and detailed in TypeScript’s documentation.
class FileHandle implements Disposable {
#handle: number;
[Symbol.dispose]() {
// Cleanup happens automatically
closeHandle(this.#handle);
}
}
{
using file = new FileHandle("data.txt");
// File closes automatically at block end
}
This feature eliminates common resource leaks by ensuring cleanup code runs predictably, similar to Python’s context managers or C#‘s using statements.
Variadic Tuple Types
Variadic tuple types, detailed in the TypeScript specification and handbook, enable powerful type-level array operations:
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];
// Type system understands the result
type Combined = Concat<[1, 2], [3, 4, 5]>; // [1, 2, 3, 4, 5]
// Real-world example
function concat<T extends unknown[], U extends unknown[]>(
arr1: T,
arr2: U
): [...T, ...U] {
return [...arr1, ...arr2];
}
const
Type Parameters
The const
modifier for generics, introduced in TypeScript 5.0 and specified in the type system, preserves literal types through generic operations:
function identity<const T>(value: T): T {
return value;
}
// Preserves exact literal types
const x = identity("hello"); // type is "hello"
const y = identity([1, 2, 3]); // type is [1, 2, 3]
const z = identity({ x: 10 }); // type is { x: 10 }
This feature is particularly useful when working with tuple types and object literals where maintaining exact types is crucial.
satisfies
Operator
The satisfies
operator, documented in the TypeScript handbook and specification, enables type validation without type widening:
type RGB = [number, number, number];
type Colors = "red" | "green" | "blue";
const palette = {
red: [255, 0, 0],
green: [0, 255, 0],
blue: [0, 0, 255],
} satisfies Record<Colors, RGB>;
// Type safety with precise inference
palette.red[0]; // number
palette.purple; // Error: property doesn't exist
Type-Only Import Attributes
Type-only import attributes, specified in the ECMAScript proposal and TypeScript implementation, improve module resolution:
import type { Config } from "./config.json" with { type: "json" };
This feature helps bundlers and runtimes better understand dependencies while maintaining type safety.
Looking Forward
Several exciting features are in development:
- Pattern matching (TC39 proposal)
- Enhanced type inference for arrays and tuples (TypeScript RFC)
- Improved partial type argument inference (TypeScript spec)
The TypeScript roadmap provides a comprehensive view of upcoming features and improvements.
Comments