TypeScriptは近年、メジャーバージョンのアップデートを重ねるごとに、型システムの表現力とデベロッパーエクスペリエンスを大幅に向上させてきましました。筆者は大規模なフロントエンド・バックエンドプロジェクトでTypeScriptを3年以上使い続けていますが、5.x系のリリースは特に実務でのインパクトが大きいと感じています。
本記事では、TypeScript 5.0から5.5までの主要な新機能を実践的な視点で解説します。単なる機能紹介ではなく、実際のプロジェクトでどう活かすかに焦点を当てます。
TypeScript 5.0では、ECMAScript Decorators提案(Stage 3)に準拠したデコレータが正式にサポートされましました。従来の実験的デコレータ(experimentalDecorators)とは異なる新しい仕様です。
function logged(
target: any,
context: ClassMethodDecoratorContext
) {
const methodName = String(context.name);
function replacementMethod(this: any, ...args: any[]) {
console.log(`[LOG] ${methodName} called with:`, args);
const result = target.call(this, ...args);
console.log(`[LOG] ${methodName} returned:`, result);
return result;
}
return replacementMethod;
}
class UserService {
@logged
findUser(id: number): string {
return `User_${id}`;
}
}
const service = new UserService();
service.findUser(42);
// [LOG] findUser called with: [42]
// [LOG] findUser returned: User_42
新しいデコレータはClassMethodDecoratorContextなどの型付きコンテキストを受け取ります。これにより、型安全なデコレータの実装が可能になりましました。NestJSなどのフレームワークを使っている方は、今後の移行を意識しておくとよいでしょう。
const修飾子をジェネリクスに付与できるようになりましました。これにより、リテラル型の推論がより厳密になります。
// constなしの場合
function withoutConst(args: T): T {
return args;
}
const a = withoutConst(['hello', 'world'] as const);
// readonly ["hello", "world"]
// constありの場合(5.0新機能)
function withConst(args: T): T {
return args;
}
const b = withConst(['hello', 'world']);
// readonly ["hello", "world"] — as constなしでリテラル型推論
API定義やルーティングテーブルなど、リテラル型を保持したい場面で非常に便利です。
TypeScript 5.1以降、関数の戻り値におけるundefinedの扱いが改善されましました。また、5.3ではswitch文での型ガードが強化されています。
// 5.1: undefinedを返す関数の型推論改善
function greet(): undefined {
// return文なしでもOK(以前はreturn undefined;が必要だった)
}
// 5.3: switch(true)パターンでの型絞り込み
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rect'; width: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rect':
return shape.width * shape.height;
}
}
ECMAScriptのImport Attributes提案に対応し、with構文でインポートにメタ情報を付与できるようになりましました。
import config from './config.json' with { type: 'json' };
console.log(config.apiUrl);
JSONモジュールのインポートが型安全に行えるため、設定ファイルの読み込みがスマートになります。
TypeScript 5.4ではNoInferユーティリティ型が導入されましました。これはジェネリクスの型推論を制御する強力なツールです。
// NoInferなしの場合
function createFSM(
initial: S,
states: S[]
): void { }
// 'idle' | 'loading' | 'typo' と推論される
createFSM('typo', ['idle', 'loading']);
// NoInferありの場合(5.4)
function createFSMSafe(
initial: NoInfer,
states: S[]
): void { }
// エラー: 'typo'は'idle' | 'loading'に含まれない
// createFSMSafe('typo', ['idle', 'loading']);
createFSMSafe('idle', ['idle', 'loading']); // OK
この機能は、意図しない型の拡張を防ぎたい場面で絶大な効果を発揮します。状態管理やイベントシステムの設計で特に重宝するでしょう。
TypeScript 5.5では、関数が型ガードとして機能する場合に、コンパイラが自動的に型述語を推論するようになりましました。
// 以前は明示的な型述語が必要だった
// function isString(x: unknown): x is string { ... }
// 5.5: 自動推論される
const values: (string | number)[] = ['a', 1, 'b', 2];
const strings = values.filter((v): v is string => typeof v === 'string');
// strings: string[]
// 正規表現による型絞り込みも改善
function process(input: string | null) {
if (typeof input === 'string' && /^\d+$/.test(input)) {
// inputはstring型として扱われる
const num = parseInt(input, 10);
}
}
TypeScript 5.x系では、型チェックのパフォーマンスも継続的に改善されています。
tsconfig.jsonのskipLibCheck使用時の改善筆者のプロジェクト(約500ファイル)では、5.0から5.5への更新で型チェック時間が約15%短縮されましました。
新バージョンへの移行にはいくつか気をつけるべき点があります。
TypeScript 5.x系は、型安全性の向上、開発体験の改善、パフォーマンスの最適化が三位一体で進化しています。特にNoInfer、型述語の自動推論、新デコレータは実務での影響が大きい機能です。プロジェクトの規模に関わらず、最新バージョンへの追従は大きなメリットがあります。まずは新しいプロジェクトから5.x系を導入し、既存プロジェクトは段階的に移行していくことをお勧めします。