TypeScript 5.4および5.5では、型推論の改善、パフォーマンスの向上、そして新しいユーティリティ型が追加されました。本記事では、これらの新機能を実践的なコード例とともに解説します。
TypeScript 5.4の新機能
NoInfer ユーティリティ型
NoInfer<T>は、型パラメータの推論を抑制する新しいユーティリティ型です。
// NoInfer - 型推論の制御
// 問題: 意図しない型推論
function createState<T>(initial: T, allowed: T[]): T {
return allowed.includes(initial) ? initial : allowed[0];
}
// "red" | "blue" ではなく string と推論される
const state1 = createState("red", ["red", "blue", "green"]);
// NoInferで解決
function createStateFixed<T>(initial: T, allowed: NoInfer<T>[]): T {
return allowed.includes(initial) ? initial : allowed[0];
}
// "red" | "blue" | "green" と正しく推論
const state2 = createStateFixed("red", ["red", "blue", "green"]);
// 実用例: イベントハンドラー
type EventMap = {
click: { x: number; y: number };
keypress: { key: string };
scroll: { scrollY: number };
};
function addEventListener<K extends keyof EventMap>(
event: K,
handler: (data: NoInfer<EventMap[K]>) => void
): void {
// 実装
}
// handlerの型がEventMap[K]から推論されない
addEventListener("click", (data) => {
// data は { x: number; y: number } として正しく型付け
console.log(data.x, data.y);
});
クロージャ内のナローイング改善
関数やコールバック内での型のナローイングが大幅に改善されました。
// 改善されたクロージャ内のナローイング
function processData(value: string | number | null) {
// TypeScript 5.3以前: コールバック内でナローイングが失われる
// TypeScript 5.4: ナローイングが維持される
if (value === null) {
return;
}
// ここでvalueは string | number
const handlers = {
// TS 5.4: クロージャ内でもナローイングが維持
process: () => {
// valueは string | number として認識
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
},
log: () => {
// ここでもナローイング維持
console.log(value);
}
};
return handlers.process();
}
// 条件分岐後のナローイング
function example(arr: string[] | null) {
if (arr === null) {
return;
}
// TypeScript 5.4: mapコールバック内でもarrはstring[]
arr.map((item) => {
// arrはnullではないことが保証
console.log(arr.length); // OK
return item.toUpperCase();
});
}
// より複雑な例
type Result<T> = { success: true; data: T } | { success: false; error: string };
function processResult<T>(result: Result<T>) {
if (!result.success) {
return null;
}
// result.dataが利用可能
const transformers = {
// クロージャ内でもresult.successがtrueであることが認識される
transform: () => {
return result.data; // TS 5.4: OK
}
};
return transformers.transform();
}
Object.groupByの型サポート
ES2024のObject.groupByとMap.groupByに型サポートが追加されました。
// Object.groupBy - ES2024対応
interface User {
id: string;
name: string;
role: 'admin' | 'user' | 'guest';
department: string;
}
const users: User[] = [
{ id: '1', name: 'Alice', role: 'admin', department: 'Engineering' },
{ id: '2', name: 'Bob', role: 'user', department: 'Engineering' },
{ id: '3', name: 'Charlie', role: 'user', department: 'Sales' },
{ id: '4', name: 'Diana', role: 'guest', department: 'Marketing' },
];
// roleでグループ化
const byRole = Object.groupBy(users, (user) => user.role);
// 型: Partial<Record<'admin' | 'user' | 'guest', User[]>>
console.log(byRole.admin); // [{ id: '1', name: 'Alice', ... }]
console.log(byRole.user); // [{ id: '2', ... }, { id: '3', ... }]
// departmentでグループ化
const byDepartment = Object.groupBy(users, (user) => user.department);
// 型: Partial<Record<string, User[]>>
// Map.groupBy - Mapを返す
const byRoleMap = Map.groupBy(users, (user) => user.role);
// 型: Map<'admin' | 'user' | 'guest', User[]>
byRoleMap.forEach((users, role) => {
console.log(`${role}: ${users.length} users`);
});
// 実用例: 日付でグループ化
interface Order {
id: string;
amount: number;
date: Date;
}
function groupOrdersByMonth(orders: Order[]) {
return Object.groupBy(orders, (order) => {
const month = order.date.toISOString().slice(0, 7); // "2025-12"
return month;
});
}
TypeScript 5.5の新機能
推論された型述語
関数の戻り値から型ガードが自動的に推論されるようになりました。
// 推論された型述語 (Type Predicates)
// TS 5.4以前: 明示的な型述語が必要
function isStringOld(value: unknown): value is string {
return typeof value === 'string';
}
// TS 5.5: 自動的に型述語が推論される
function isString(value: unknown) {
return typeof value === 'string';
}
// 推論される型: (value: unknown) => value is string
// 配列フィルターでの活用
const mixed: (string | number | null)[] = ['a', 1, null, 'b', 2];
// TS 5.4以前: filterの結果は (string | number | null)[] のまま
const stringsOld = mixed.filter((x): x is string => typeof x === 'string');
// TS 5.5: 自動的にstring[]と推論
const strings = mixed.filter((x) => typeof x === 'string');
// 型: string[]
// nullの除去も自動
const notNull = mixed.filter((x) => x !== null);
// 型: (string | number)[]
// 複雑な例
interface User {
id: string;
name: string;
email?: string;
}
const users: (User | null)[] = [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
null,
{ id: '2', name: 'Bob' },
];
// 自動的に型が絞り込まれる
const validUsers = users.filter((user) => user !== null && user.email);
// 型: User[] (emailが存在するユーザーのみ)
正規表現の構文チェック
正規表現リテラルの構文チェックが追加されました。
// 正規表現の構文チェック
// TS 5.5: 無効な正規表現はコンパイルエラー
// エラー: 無効なエスケープシーケンス
// const invalid1 = /\p/;
// エラー: 不完全な文字クラス
// const invalid2 = /[a-/;
// エラー: 無効な量指定子
// const invalid3 = /a{}/;
// 有効な正規表現
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phone = /^\d{3}-\d{4}-\d{4}$/;
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
// Unicodeプロパティエスケープ(uフラグが必要)
const japanese = /\p{Script=Hiragana}+/u;
const emoji = /\p{Emoji}/u;
// 名前付きキャプチャグループ
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-02'.match(datePattern);
if (match?.groups) {
const { year, month, day } = match.groups;
console.log(year, month, day); // "2025", "01", "02"
}
独立した宣言 (Isolated Declarations)
isolatedDeclarationsオプションにより、型宣言の生成を高速化できます。
// tsconfig.json
{
"compilerOptions": {
"isolatedDeclarations": true,
"declaration": true
}
}
// isolatedDeclarations: true の場合、
// 関数の戻り値や変数の型を明示する必要がある
// ❌ エラー: 戻り値の型が必要
// export function add(a: number, b: number) {
// return a + b;
// }
// ✅ OK: 戻り値の型を明示
export function add(a: number, b: number): number {
return a + b;
}
// ❌ エラー: 変数の型が必要
// export const config = { port: 3000, host: 'localhost' };
// ✅ OK: 型を明示
export const config: { port: number; host: string } = {
port: 3000,
host: 'localhost'
};
// 利点:
// - ビルドの並列化が可能に
// - 型チェックなしで.d.tsを生成可能
// - モノレポでの高速ビルド
新しいSet メソッドの型サポート
ES2024のSetメソッドに型サポートが追加されました。
// 新しいSetメソッド
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
// union: 和集合
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6]
// intersection: 積集合
const intersection = setA.intersection(setB);
console.log([...intersection]); // [3, 4]
// difference: 差集合
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2]
// symmetricDifference: 対称差
const symmetricDiff = setA.symmetricDifference(setB);
console.log([...symmetricDiff]); // [1, 2, 5, 6]
// isSubsetOf: 部分集合判定
const subset = new Set([2, 3]);
console.log(subset.isSubsetOf(setA)); // true
// isSupersetOf: 上位集合判定
console.log(setA.isSupersetOf(subset)); // true
// isDisjointFrom: 互いに素か判定
const setC = new Set([7, 8, 9]);
console.log(setA.isDisjointFrom(setC)); // true
// 実用例: タグフィルタリング
interface Article {
id: string;
title: string;
tags: Set<string>;
}
function filterByTags(articles: Article[], requiredTags: Set<string>): Article[] {
return articles.filter(article =>
requiredTags.isSubsetOf(article.tags)
);
}
パフォーマンス改善
型チェックの高速化
// TypeScript 5.4/5.5 パフォーマンス改善
// 1. モノモーフィック化された型チェック
// - 同じ形状のオブジェクトの処理が高速化
// 2. 条件型の最適化
type IsString<T> = T extends string ? true : false;
// 内部的なキャッシングが改善
// 3. プロジェクト参照のビルド最適化
// tsconfig.json
{
"compilerOptions": {
"incremental": true,
"composite": true,
// 5.5で追加
"isolatedDeclarations": true
},
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" }
]
}
// 4. エディタの応答性向上
// - 自動インポートの提案が高速化
// - リファクタリング操作の改善
実践的な型パターン
改善された型ユーティリティ
// 実践的な型パターン
// 1. より安全なディープパーシャル
type DeepPartial<T> = T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
interface Config {
server: {
port: number;
host: string;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
pool: number;
};
}
// 部分的な設定更新
function updateConfig(partial: DeepPartial<Config>): Config {
// マージロジック
return {} as Config;
}
updateConfig({
server: {
ssl: {
enabled: true
}
}
});
// 2. 型安全なイベントシステム
type EventMap = {
'user:login': { userId: string; timestamp: Date };
'user:logout': { userId: string };
'order:created': { orderId: string; total: number };
};
class TypedEventEmitter<T extends Record<string, unknown>> {
private handlers = new Map<keyof T, Set<(data: any) => void>>();
on<K extends keyof T>(event: K, handler: (data: T[K]) => void): () => void {
if (!this.handlers.has(event)) {
this.handlers.set(event, new Set());
}
this.handlers.get(event)!.add(handler);
return () => this.handlers.get(event)?.delete(handler);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
this.handlers.get(event)?.forEach(handler => handler(data));
}
}
const emitter = new TypedEventEmitter<EventMap>();
// 型安全なイベントハンドリング
emitter.on('user:login', (data) => {
// data は { userId: string; timestamp: Date }
console.log(data.userId, data.timestamp);
});
// 3. 条件付き必須プロパティ
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>> &
{ [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys];
interface SearchParams {
query?: string;
categoryId?: string;
tags?: string[];
}
// 少なくとも1つの検索条件が必須
type ValidSearchParams = RequireAtLeastOne<SearchParams, 'query' | 'categoryId' | 'tags'>;
function search(params: ValidSearchParams) {
// 実装
}
// OK
search({ query: 'test' });
search({ categoryId: '123' });
search({ query: 'test', tags: ['a', 'b'] });
// エラー
// search({}); // 少なくとも1つの条件が必要
マイグレーションガイド
5.3 → 5.4/5.5 への移行
# アップグレード
npm install typescript@latest
# 型チェック
npx tsc --noEmit
# よくある修正点
// 1. 新しいナローイング挙動への対応
// 一部のコードで型が正しく推論されるようになり、
// 以前は必要だった型アサーションが不要になる場合がある
// Before (TS 5.3)
function example(value: string | null) {
if (value === null) return;
const fn = () => {
// value as string が必要だった
return (value as string).toUpperCase();
};
}
// After (TS 5.4+)
function exampleNew(value: string | null) {
if (value === null) return;
const fn = () => {
// 型アサーション不要
return value.toUpperCase();
};
}
// 2. Object.groupBy の使用
// lib設定の確認が必要
// tsconfig.json
{
"compilerOptions": {
"lib": ["ES2024"] // または "ESNext"
}
}
まとめ
TypeScript 5.4/5.5は、型推論とパフォーマンスの大幅な改善をもたらしました。
主要な新機能
| 機能 | バージョン | 影響 |
|---|---|---|
| NoInfer | 5.4 | 型推論の制御 |
| クロージャナローイング | 5.4 | コード品質向上 |
| Object.groupBy | 5.4 | ES2024対応 |
| 推論された型述語 | 5.5 | filter等の改善 |
| isolatedDeclarations | 5.5 | ビルド高速化 |
| 正規表現チェック | 5.5 | エラー検出強化 |
アップグレードの推奨
- 新規プロジェクト: 最新版を採用
- 既存プロジェクト: 段階的に移行
- 大規模プロジェクト: isolatedDeclarationsの活用
TypeScriptの進化により、より安全で効率的なコードが書けるようになっています。