3月1日、TypeScript 5.8がリリースされた。

この記事では、TypeScript 5.8の主な新機能や変更点について簡潔に紹介する。
本記事は、以下のエキスパートに監修していただきました:
新機能・変更点の概要
return
文内の条件式に対する型チェックの強化
以下のようにreturn
文の中で条件演算子を使う場合、TypeScript 5.8では各分岐が関数の戻り値型と整合しているかをより厳密にチェックするようになった。
declare const untypedCache: Map<any, any>;
function getUrlObject(urlString: string): URL {
return untypedCache.has(urlString) ?
untypedCache.get(urlString) :
urlString;
// ~~~~~~~~~
// error! Type 'string' is not assignable to type 'URL'.
}
本来ここではurlString
をnew URL(urlString)
のように変換しなければならないが、それを忘れていた場合でも5.8ではエラーとして検出されるようになった(以前は条件演算子が any | string
型となり、 any
型の影響で型チェックが働かなかった)。
--module nodenext
におけるCommonJSからのESM読み込みサポート
Node.jsは長らくCommonJSとESMを併用してきたが、以下のような制限が存在した。
- ESMファイルはCommonJSファイルを`import`できる
- CommonJSファイルはESMファイルを`require()`できない
Node.js 22ではこの制限が緩和され、トップレベルのawait
を含まないESMファイルであれば、CommonJS側からrequire("esm")
で読み込めるようになった。これによってライブラリ制作者がESM対応を提供しやすくなる。
TypeScript 5.8では、--module nodenext
を指定することで、このNode.js 22以降の動作をエラーなく扱えるようになった。ただし、Node.js 22未満のバージョンでは依然としてrequire()
によるESMの読み込みは認められていないため、古い環境では従来の--module node16
などを利用するほうが安全である。
--module node18
フラグの安定版導入
TypeScript 5.8では、新たに安定版として--module node18
フラグが追加された。これはNode.js 18を利用する環境を想定し、--module nodenext
ほど先進的でない挙動を定義している。具体的には、
- `node18`ではESMファイルの`require()`を許可しない(`nodenext`では許可される)
- `node18`ではimport assertions(現在は非推奨)を許可する(`nodenext`ではエラーになる)
Node.js 18を固定運用したい場合に安定した設定が必要であれば、このフラグを利用するとよい。
--erasableSyntaxOnly
オプション
Node.js 23.6では、TypeScriptファイルを直接実行する機能が試験的に解除された。ただし、この機能はランタイムに影響のない「TypeScript特有の部分を単に消すだけでJavaScriptにトランスパイルできる構文」しかサポートしない。つまり、次のような構文は利用できない。
- `enum`宣言
- 実行時コードを含む`namespace`や`module`
- クラスのパラメータプロパティ
- `import =`エイリアス
例として、以下のコードはサポートされない。
// ❌ error: A namespace with runtime code.
namespace container {
foo.method();
export type Bar = string;
}
// ❌ error: An `import =` alias
import Bar = container.Bar;
class Point {
// ❌ error: Parameter properties
constructor(public x: number, public y: number) { }
}
// ❌ error: An enum declaration.
enum Direction {
Up,
Down,
Left,
Right,
}
こうした制限をTypeScriptレイヤーで早期に検出するため、5.8では--erasableSyntaxOnly
フラグを導入している。これを有効にすると、上記のような「ランタイム動作を持つTypeScript独自構文」に対してエラーを発生させる。通常は--verbatimModuleSyntax
などと合わせて使用し、モジュールのインポート構文をそのまま残す設定と組み合わせることが推奨される。
--libReplacement
フラグ
TypeScript 4.5以降、@typescript/lib-*
というパッケージを通じて標準の型定義(lib)を差し替える仕組みが存在した。例えば package.json
に以下のように指定することで、domライブラリをパッケージ @types/web
の特定のバージョンにロックできる。
{
"devDependencies": {
"@typescript/lib-dom": "npm:@types/web@0.0.199"
}
}
しかし、プロジェクトの大半においてはこの機能を使用しないにもかかわらず、TypeScriptは常にnode_modules
を監視して差し替えパッケージの存在をチェックしていた。
5.8では--libReplacement
フラグが導入され、不要な場合は明示的に--libReplacement false
で無効化できるようになった。今後この挙動がデフォルトでfalseになる可能性があるため、lib置き換え機能を使う場合は--libReplacement true
を指定することが望ましい。
ビルドや監視モードでのパフォーマンス改善
5.8ではプロジェクト読み込みや更新処理におけるパフォーマンス面で最適化が行われている。具体的にはパス正規化時の配列生成を削減したり、--watch
モードやエディター上での少量の編集であればtsconfig.json
のオプション検証を再実行しないなど、無駄な処理を減らす仕組みが導入されている。そのため、大規模プロジェクトでも編集応答が早くなることが期待される。
--module nodenext
におけるインポートアサーションの制限
インポートアサーションは、もともとassert { type: "json" }
などの形式でJSONファイルなどを読み込むために提案されていたが、新たにwith { type: "json" }
と置き換えられる形になった。Node.js 22ではassert
構文が非サポートとなったため、TypeScript 5.8でも--module nodenext
を指定した場合にはエラーが発生するようになっている。
import data from "./data.json" assert { type: "json" };
// ~~~~~~
// error! Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'
今後の展望
次のバージョンはTypeScript 5.9であり、機能の詳細や正確なスケジュールは今後発表される予定である。npm install typescript@next
を利用するか、VS CodeのTypeScript Nightly拡張を導入することで、5.9の早期バージョンを試すことができる。
TypeScript 5.8自体はすでに利用可能であり、多くの改良によって開発体験が向上している。ぜひこの機会にアップデートして、最新機能を試してみるとよいだろう。
詳細は[Announcing TypeScript 5.8]を参照していただきたい。