TSConfig文件详解18
编译器配置项-compilerOptions
输出相关配置项02
降级迭代-downlevelIteration
降级是 TypeScript 的术语,表示转换为旧版 JavaScript。downlevelIteration
选项是为了支持现代JavaScript的迭代概念能够更准确地在旧版 JavaScript 中运行。
ECMAScript 6 添加了几个新的迭代语法:for / of
循环(for (el of arr)
)、数组展开([a, ...b]
)、参数展开(fn(...args)
)和 Symbol.iterator
。如果存在 Symbol.iterator
已经被实现,则 downlevelIteration
允许在 ES5 环境中更准确地使用这些迭代原语。
示例1:在for/of
语法中的作用
有以下TypeScript
代码:
const str = "Hello!";
for (const s of str) {
console.log(s);
}
未启用downlevelIteration
时,一个在Object
上的for/of
循环将降级为传统的for
循环:
"use strict";
var str = "Hello!";
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
var s = str_1[_i];
console.log(s);
}
这通常是人们所期望的,但它并不 100% 符合 ECMAScript 迭代协议。某些字符串,例如表情符号 (😜),其 .length
为 2(甚至更大!),但在 for-of
循环中应作为 1 个单位进行迭代。有关更详细的解释,请参阅 Jonathan New 的这篇博文。
启用downlevelIteration
后,TypeScript 将使用辅助函数检查Symbol.iterator
实现(原生或 polyfill)。如果缺少此实现,您将回退到基于索引的迭代。
"use strict";
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
var str = "Hello!";
try {
for (var str_1 = __values(str), str_1_1 = str_1.next(); !str_1_1.done; str_1_1 = str_1.next()) {
var s = str_1_1.value;
console.log(s);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
}
finally { if (e_1) throw e_1.error; }
}
可以通过tslib
中的importHelpers
减少内联 JavaScript 的数量:
"use strict";
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
var str = "Hello!";
try {
for (var str_1 = __values(str), str_1_1 = str_1.next(); !str_1_1.done; str_1_1 = str_1.next()) {
var s = str_1_1.value;
console.log(s);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
}
finally { if (e_1) throw e_1.error; }
}
注意: 如果运行时不存在Symbol.iterator
,那么启用downlevelIteration
并不能提高合规性。
示例2:展开数组上的作用
下边是展开数组的一个示例:
// Make a new array whose elements are 1 followed by the elements of arr2
const arr = [1, ...arr2];
根据描述,降级到 ES5 听起来很容易:
// The same, right?
const arr = [1].concat(arr2);
但是,在某些罕见情况下,情况会有所不同。
例如,如果源数组缺少一个或多个的空元素,则扩展语法会将每个空元素替换为undefined
,而.concat
则会保留它们。
// Make an array where the element at index 1 is missing
let arrayWithHole = ["a", , "c"];
let spread = [...arrayWithHole];
let concatenated = [].concat(arrayWithHole);
console.log(arrayWithHole);
// [ 'a', <1 empty item>, 'c' ]
console.log(spread);
// [ 'a', undefined, 'c' ]
console.log(concatenated);
// [ 'a', <1 empty item>, 'c' ]
与for / of
语法一样,启用downlevelIteration
将使用Symbol.iterator
(如果存在) 来更准确地模拟 ES 6 行为