9月10日、MicrosoftはTypeScript 5.6のリリースを発表した。
今回のリリースでは、多くの新機能や改良が含まれており、特にバグの早期発見とコードの安全性が強化されている。以下は、TypeScript 5.6の主要な新機能と改善点である。
真偽チェックの厳格化
TypeScript 5.6では、コード内の真偽値チェックに対する厳格な制約が追加された。具体的には、常に真(truthy)または偽(falsy)となる式に対してエラーが発生する。これにより、意図しない条件式によるバグを未然に防ぐことができる。
以下のコード例では、意図しない真偽式が検出され、エラーとして扱われる。
if (/0x[0-9a-f]/) {
// エラー: この式は常に真となる。(.test()の呼び出しを忘れたのかもしれない)
}
if (x => 0) {
// エラー: この式は常に真となる。(比較演算子を使いたかったのに間違えたのだろう)
}
function isValid(value: string | number, options: any, strictness: "strict" | "loose") {
if (strictness === "loose") {
value = +value;
}
return value < options.max ?? 100;
// エラー: ??の左側の式が常にnullishではないため、右側の式に到達できない。
}
イテレーターヘルパーメソッドの追加
JavaScriptには、Map.entries()の戻り値や関数ジェネレーターなど、「繰り返し処理を行えるオブジェクト」を表す概念がある。
それらはイテラブル([Symbol.iterator]()
を呼び出してイテレータを取得できるもの)とイテレータ(next()
メソッドを持ち、次の値を取得できるもの)というインターフェースで表されているが、ほとんどの場合、これらについて深く考える必要はなく、for
/of
ループやスプレッド演算子([...]
)で簡単に使うことができる。
TypeScriptではこれらをIterable
とIterator
という型でモデル化しており、さらにIterableIterator
という、イテラブルでもありイテレータでもあるものを表す型も提供している。
しかしこれらは、配列(Array)とは全く異なるインターフェースとして扱われていたため、配列が持つmap
やfilter
、reduce
といったメソッドを持ち合わせていないことが不便、かつコーディングミスの原因となっていた。そこで、ECMAScriptの最近の提案により、JavaScriptで生成されるほとんどのイテレータに対して、これらのメソッド(およびそれ以上のメソッド)を追加することが提案された。
TypeScript 5.6ではそうしたECMAScript側の提案をもとに、イテレータにもmapやfilterといったメソッドが追加された。これにより、配列のように簡単にデータの変換や抽出ができるようになった。
例えば、以下の例では、連続する整数を生成するジェネレータ関数に対して、mapメソッドを使って2倍の数を作り、takeメソッドを使って最初の5つの数だけを取り出している。
function* positiveIntegers() {
let i = 1;
while (true) {
yield i;
i++;
}
}
const evenNumbers = positiveIntegers().map(x => x * 2);
// 出力:
// 2
// 4
// 6
// 8
// 10
for (const value of evenNumbers.take(5)) {
console.log(value);
}
同様に、Map
やSet
にあるkeys()
、values()
、entries()
メソッドでも、同じようなことができる。
function invertKeysAndValues<K, V>(map: Map<K, V>): Map<V, K> {
return new Map(
map.entries().map(([k, v]) => [v, k])
);
}
さらに、新しいIterator
オブジェクトを拡張することも可能だ。
/**
* 無限に`0`を生成するストリーム。
*/
class Zeroes extends Iterator<number> {
next() {
return { value: 0, done: false } as const;
}
}
const zeroes = new Zeroes();
// 無限に`1`を生成するストリームに変換。
const ones = zeroes.map(x => x + 1);
また、既存のIterable
やIterator
をこの新しい型に適応させることもできる。
Iterator.from(...).filter(someFunction);
これらの新しいメソッドは、最新のJavaScriptランタイムで実行するか、Iterator
オブジェクト用のポリフィルを使用すれば動作する。
ビルトインイテレータチェックの厳格化と--strictBuiltinIteratorReturn
TypeScript 5.6では、Iterator
のnext()
メソッドの戻り値であるIteratorResult
型に対する厳格なチェックが導入された。この変更により、イテレータの誤った使用を未然に防ぐことができるようになった。
例えば、以下のようにtoUpperCase
メソッドを誤って使用しているコードは、適切なエラーチェックが行われる。
function* uppercase(iter: Iterator<string, any>) {
while (true) {
const { value, done } = iter.next();
yield value.toUppercase(); // エラー: 'toUppercase'は存在しないメソッド
if (done) {
return;
}
}
}
任意のモジュール識別子のサポート
JavaScriptでは、モジュール識別子として無効な識別子名を文字列リテラルとして使用することが許可されている。TypeScript 5.6では、これに対応する機能が追加され、次のように特殊な識別子を使用できるようになった。
const banana = "🍌";
export { banana as "🍌" };
この機能は、他の言語との相互運用性を高め、WebAssemblyなどの境界を跨いだコードのやり取りにおいて特に有用である。
6. --noUncheckedSideEffectImports
オプション
TypeScript 5.6では、新しいコンパイラオプション--noUncheckedSideEffectImports
が導入され、存在しないモジュールのインポートに対してエラーが発生するようになった。これにより、サイドエフェクトのあるインポートに対する信頼性が向上し、モジュールの取り扱いがより厳密に行われる。
import "some-nonexistent-module";
// エラー: モジュール 'some-nonexistent-module' が見つかりません
--noCheck
オプション
TypeScript 5.6では、型チェックをスキップするための--noCheck
オプションが追加された。このオプションを使用することで、ビルド時に型チェックを行わず、ファイルの出力をより迅速に行うことができる。特に、開発の早い段階での迅速なフィードバックが必要な場合に役立つ。
中間エラーを許容するビルドモード
プロジェクトの参照関係において、ビルド中にエラーが発生しても他のプロジェクトのビルドを続行することが可能になった。これにより、依存関係のあるプロジェクト間の柔軟性が向上し、エラーが発生してもビルド全体が中断されることがなくなった。
詳細はAnnouncing TypeScript 5.6を参照していただきたい。