TypeScript 3.3
改进的可调用联合类型行为
在先前版本的 TypeScript 中,只有当可调用类型的联合具有完全相同的参数列表时,才能调用它们。
type Fruit = "apple" | "orange";
type Color = "red" | "orange";
type FruitEater = (fruit: Fruit) => number; // 吃水果并评分
type ColorConsumer = (color: Color) => string; // 消费并描述颜色
declare let f: FruitEater | ColorConsumer;
// 无法调用缺少调用签名的表达式。
// 类型 'FruitEater | ColorConsumer' 没有兼容的调用签名。ts(2349)
f("orange");然而,在上面的例子中,FruitEater 和 ColorConsumer 都应该能够接受字符串 "orange",并分别返回 number 或 string。
在 TypeScript 3.3 中,这不再是错误。
type Fruit = "apple" | "orange";
type Color = "red" | "orange";
type FruitEater = (fruit: Fruit) => number; // 吃水果并评分
type ColorConsumer = (color: Color) => string; // 消费并描述颜色
declare let f: FruitEater | ColorConsumer;
f("orange"); // 有效!返回 'number | string'。
f("apple"); // 错误 - 类型 '"apple"' 的参数不能赋给类型 '"orange"' 的参数。
f("red"); // 错误 - 类型 '"red"' 的参数不能赋给类型 '"orange"' 的参数。在 TypeScript 3.3 中,这些签名的参数被交叉在一起以创建一个新的签名。
在上面的例子中,参数 fruit 和 color 被交叉成一个新的类型为 Fruit & Color 的参数。 Fruit & Color 实际上等同于 ("apple" | "orange") & ("red" | "orange"),这又等价于 ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange")。 这些不可能的交叉中的每一个都简化为 never,我们只剩下 "orange" & "orange",即 "orange"。
注意事项
此新行为仅在联合中最多有一个类型具有多个重载,且最多有一个类型具有泛型签名时才会触发。 这意味着像 number[] | string[] 上的方法(如 map,它是泛型的)仍然不可调用。
另一方面,像 forEach 这样的方法现在可以调用,但在 noImplicitAny 下可能存在一些问题。
interface Dog {
kind: "dog";
dogProp: any;
}
interface Cat {
kind: "cat";
catProp: any;
}
const catOrDogArray: Dog[] | Cat[] = [];
catOrDogArray.forEach(animal => {
// ~~~~~~ 错误!
// 参数 'animal' 隐式具有 'any' 类型。
});这在 TypeScript 3.3 中仍然更强大,添加显式类型注解即可工作。
interface Dog {
kind: "dog";
dogProp: any;
}
interface Cat {
kind: "cat";
catProp: any;
}
const catOrDogArray: Dog[] | Cat[] = [];
catOrDogArray.forEach((animal: Dog | Cat) => {
if (animal.kind === "dog") {
animal.dogProp;
// ...
} else if (animal.kind === "cat") {
animal.catProp;
// ...
}
});在 --build --watch 中为复合项目增加增量文件监视
TypeScript 3.0 引入了一个用于构建结构的新功能,称为“复合项目”。 其部分目标是确保用户可以将大型项目分解为更小的部分,这些部分可以快速构建并保留项目结构,同时不损害现有的 TypeScript 体验。 借助复合项目,TypeScript 可以使用 --build 模式仅重新编译一组项目和依赖项。 你可以将其视为优化项目间构建。
TypeScript 2.7 还通过新的增量“构建器”API 引入了 --watch 模式构建。 类似地,整个思想是此模式仅重新检查和重新输出已更改的文件或依赖项可能影响类型检查的文件。 你可以将其视为优化项目内构建。
在 3.3 之前,使用 --build --watch 构建复合项目实际上并未使用此增量文件监视基础结构。 在 --build --watch 模式下更新一个项目会强制对该项目进行完整构建,而不是确定该项目中哪些文件受到影响。
在 TypeScript 3.3 中,--build 模式的 --watch 标志确实也利用了增量文件监视。 这可能意味着在 --build --watch 下构建速度显著加快。 在我们的测试中,此功能使原始 --build --watch 时间的构建时间减少了 50% 到 75%。 你可以在该更改的原始拉取请求中阅读更多信息以查看具体数字,但我们相信大多数复合项目用户将在此处看到显著的改进。