改进了调用联合类型的行为
在 TypeScript 的早期版本中, 不同的联合类型如果想互相访问其取值, 它们参数的取值列表必须完全一致才行.
- type Fruit = "apple" | "orange";
- type Color = "red" | "orange";
- type FruitEater = (fruit: Fruit) => number; // 吃水果并对它们排名
- type ColorConsumer = (color: Color) => string; // 处理颜色并对其进行描述
- declare let f: FruitEater | ColorConsumer;
- // Cannot invoke an expression whose type lacks a call signature.
- // 无法调用这个表达式, 因为缺少调用签名类型.
- // Type 'FruitEater | ColorConsumer' has no compatible call signatures.ts(2349)
- // 类型'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"); // error - Argument of type '"red"' is not assignable to parameter of type '"orange"'.
- f("red"); // error - Argument of type '"red"' is not assignable to parameter of type '"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 => {
- // ~~~~~~ error!
- // 参数'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 还引入了 --watch 模式, 通过新的增量 "构建器"API 进行构建. 该模式只重新检查和传送被修改的, 可能会影响类型检查的源码文件和依赖. 您可以将其视为对项目内构建的优化.
在 3.3 版本之前, 在使用 --build --watch 构建复合项目时, 实际上并没有使用这种监视增量文件的基础结构. 在 --build --watch 模式下, 如果一个项目中有了更新, 将会强制完全重新构建该项目, 而不是检查项目中有哪些文件受到影响.
在 TypeScript 3.3 中, --build 模式的 --watch 标志也可以利用增量文件机制进行监视了. 这可能意味着在 --build --watch 模式下构建速度能将会更快. 在我们的测试中, 此功能使 --build --watch 的构建时间比原来缩短了 50%到 75%. 您可以阅读与文件修改时的原始拉取请求相关的更多内容 https://github.com/Microsoft/TypeScript/pull/29161 来查看这些数据, 我们相信大多数使用复合项目的用户将会在此处得到更好的体验.
来源: https://juejin.im/post/5c48286a6fb9a049c43e0247