概要
https://www.typescriptlang.org/tsconfig#downlevelIteration
"downlevelIteration": true
Downleveling(ダウンレベリング)というのは、古いバージョンの JS コードにコンパイルするという意味の TypeScript 用語です。
targetがES3
またはES5
の際に、ジェネレータのyield*
やfor..of
構文などのES6から追加されたイテレーション系の記法を、より正確なコードにコンパイルしたい場合にtrue
にします。
TypeScript 2.3 で導入されました。
詳細
ES6 で、JS にはイテレータ(Symblo.iterator
)と共に
for-of
ループ- 配列展開(
[a, ...b]
) - 引数展開(
fn(..args)
)
といったイテレーション系の記法が追加されました。
これらの記法はデフォルトでも基本的には問題なくコンパイルできますが、一部の条件でコンパイルエラーになります。
それらの記法は内部でイテレータを使用しているわけですが、ES5 以下の古い仕様にはそもそもイテレータが存在しないので、簡易なコードでは完全に再現できず、特定の条件でランタイムエラーを吐きます。
それを防ぐために、このオプションをtrue
にすると、実行時にSymbol.iterator
を探し存在すれば反復処理にイテレータを使うようになる Polyfill を JS コードに追加します。
この際、Symbol.iterator
は実行環境のネイティブ実装でもサードパーティーの Polyfill でも大丈夫です。
逆に言うと、実行環境にSymbol.iterator
の実装が存在しなければ、このオプションをtrue
にしてコンパイルが通ったところで、コンパイル結果のコードは依然としてランタイムエラーの危険性を持ったままになります。
これ以上細かい話は公式ドキュメントをご覧ください。
コンパイルエラーの例
たとえば、配列・文字列以外の iterable なオブジェクトに対してこれらの新しい記法を実行しようとすると、targetがES3
・ES5
の場合にコンパイルエラーになります。
// index.ts
// これは配列なのでOK
const arr = [1, 2, 3];
for (const value of arr) {
console.log(value);
}
// Setはiterableだけど配列ではないのでエラー
const map = new Set([1, 2, 3]);
for (const value of map) {
console.log(value);
}
src/index.ts:9:21 - error TS2569: Type 'Set<number>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
他にも、ジェネレータのyield*
を配列・文字列以外で使用すると同様のエラーが出ます。
// index.ts
// これは配列なのでOK
function* func() {
while (true) {
const arr = [1, 2, 3];
yield* arr;
}
}
// Mapはiterablだけど配列・文字列ではないのでエラー
function* func() {
while (true) {
const map = new Map<string, string>();
map.set("hoge", "HOGE");
yield* map;
}
}
src/index.ts:14:12 - error TS2569: Type 'Map<string, string>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
ちなみに、これは自作の iterable なオブジェクトでも同様です。
// index.ts
class MyIterator {
count = 0;
max: number;
constructor(max: number) {
this.max = max;
}
next() {
const done = this.count > this.max;
const value = done ? undefined : this.count;
this.count = this.count + 1;
return { value, done };
}
}
const iterator = new MyIterator(10);
// iterableなオブジェクトは[Symbol.iterator]プロパティがイテレータを返す必要がある。
// 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols
const iterable = {
[Symbol.iterator]() {
return iterator;
},
};
// `iterable`オブジェクト はiterableだけど配列ではないのでエラー
for (const value of iterable) {
console.log(value);
}
// `iterable`オブジェクト はiterableだけど配列ではないのでエラー
function* func() {
while (true) {
yield* iterable;
}
}
イテレータも iterable なオブジェクトも自分で書いたとして、このコードのコンパイル結果は
src/index.ts:29:21 - error TS2569: Type '{ [Symbol.iterator](): MyIterator; }' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
です。
これらは、"downlevelIteration": true
にすることでコンパイルが通るようになります。