TypeScript 5.4は2024年3月6日にreleaseされました。この記事は5.4固有の型推論とlibrary定義に限定し、5.5の機能は**TypeScript 5.5の記事**へ分離します。
NoInfer
記事情報: 2025年12月2日初出。TypeScript 5.4公式release記事を2026年7月25日に再確認しています。
generic functionでは複数のargumentが同じtype parameterの推論候補になります。候補にしたくない位置をNoInfer<T>で囲むと、その値からTを推論せず、ほかのargumentから決まった型へ適合するかだけを確認できます。
function createTheme<C extends string>(
colors: C[],
initial?: NoInfer<C>,
) {
return { colors, initial };
}
createTheme(["red", "green"], "red");
createTheme(["red", "green"], "blue");
// ~~~~~~
// "red" | "green" に含まれないためerror
従来は2つ目のtype parameterを作るworkaroundが使われましたが、constraintだけのparameterが増え、意図しない推論を許す場合がありました。
NoInferは値のruntime validationを行いません。外部JSONなど実行時の入力にはschema validationが別に必要です。また、推論結果を理解しづらくするほど多用せず、「このargumentは候補集合を広げてはいけない」というAPI境界に使います。
クロージャ内のnarrowing
TypeScriptは変数へ最後に代入した位置を分析し、その後変更されないと判断できる場合、closure内でも型の絞り込みを保持します。
function getUrls(input: string | URL, names: string[]) {
if (typeof input === "string") {
input = new URL(input);
}
return names.map((name) => {
input.searchParams.set("name", name);
return input.toString();
});
}
5.4ではmap callback作成前の最後の代入を見て、callback内のinputをURLとして扱えます。
ただしnested function内で対象変数を再代入する場合、いつ実行されるか保証できないためnarrowingは維持されません。
function example(value: string | undefined) {
if (value === undefined) return;
setTimeout(() => {
value = undefined;
});
return () => value.toUpperCase();
// ~~~~~
// 再代入の可能性がある
}
型errorを消すためだけにassertionを加えず、変数をconstへ写す、mutationを分離するなどcontrol flowを明確にします。
Object.groupByとMap.groupByの型
TypeScript 5.4はECMAScriptのObject.groupByとMap.groupByの型定義を追加しました。
const values = [1, 2, 3, 4];
const grouped = Object.groupBy(values, (value) =>
value % 2 === 0 ? "even" : "odd",
);
console.log(grouped.even);
一般にはcallbackがすべてのkeyを必ず生成する保証がないため、resultのpropertyはoptionalです。strictNullChecksでは存在確認が必要です。
const evenTotal =
grouped.even?.reduce((sum, value) => sum + value, 0) ?? 0;
これらはTypeScript独自のruntime実装ではなくJavaScript APIの型です。compileが通っても実行環境にAPIがなければ動きません。release当時はtarget: "esnext"または適切なlib設定が必要と案内されていました。現在はtarget browser・Node.jsとpolyfill方針を確認します。
Map.groupByはobject property key以外の値もgroup keyに使いたい場合に選択できます。
Promise.resolveの型改善
5.4ではPromise.resolveの型がAwaitedを使う形へ改善され、Promiseを受け取ったgeneric codeで返却型をより正確に表せるようになりました。独自utilityでPromiseをunwrapしていた場合は推論結果が変わる可能性があります。
型推論の改善はruntime behaviorを変えません。compile errorが新しく出た場合、以前の型が過度に広かったのか、public APIのannotationが不足しているのかを確認します。
Auto-importとmodule resolution
5.4はpackageのexportsにあるsubpath importをauto-import候補でより適切に扱い、moduleResolution: "bundler"と"preserve"の組み合わせなどmodule関連も改善しました。
package開発ではeditorの候補だけで判断せず、生成されるimport pathがpackage exportsに含まれ、runtime bundlerでもresolveできるかをtestします。
Deprecated optionの扱い
5.0でdeprecatedになったcompiler optionは5.4で機能しなくなったものがあります。代表例にはcharset、importsNotUsedAsValues、preserveValueImportsなどが含まれます。ignoreDeprecations: "5.0"でwarningだけを隠していたprojectは設定を削除・置換します。
npx tsc --showConfig
extended tsconfigを含む最終設定を確認し、古いoptionを残さないようにします。
移行手順
npm install --save-dev typescript@5.4
npx tsc --noEmit
- 現在のTypeScriptでerrorを解消する
- 5.4へ固定して型checkする
- public libraryはdeclaration fileの差分を見る
- testとbuildを実行する
- editorがworkspace版TypeScriptを使うか確認する
TypeScriptのminor updateではruntime codeが同じでも推論結果が変わります。anyやassertionで一括回避せず、errorごとに意図した型を確認してください。
5.4は現在のlatest版ではありません。新規projectではframeworkが対応する現在のstable版を使い、この記事は5.4で型の挙動が変わった理由を追う資料として利用してください。複数versionを飛び越えて更新する場合も、各release noteを順番に確認するとerrorの発生源を特定しやすくなります。