改进了调用联合的行为类型
¥Improved behavior for calling union types
在早期版本的 TypeScript 中,只有当可调用类型的联合具有相同的参数列表时,才能调用它们。
¥In prior versions of TypeScript, unions of callable types could only be invoked if they had identical parameter lists.
ts
type Fruit = "apple" | "orange";type Color = "red" | "orange";type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruittype ColorConsumer = (color: Color) => string; // consumes and describes the colorsdeclare let f: FruitEater | ColorConsumer;// Cannot invoke an expression whose type lacks a call signature.// Type 'FruitEater | ColorConsumer' has no compatible call signatures.ts(2349)f("orange");
但是,在上面的例子中,FruitEater
和 ColorConsumer
都应该能够接受字符串 "orange"
,并返回 number
或 string
。
¥However, in the above example, both FruitEater
s and ColorConsumer
s should be able to take the string "orange"
, and return either a number
or a string
.
在 TypeScript 3.3 中,这不再是一个错误。
¥In TypeScript 3.3, this is no longer an error.
ts
type Fruit = "apple" | "orange";type Color = "red" | "orange";type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruittype ColorConsumer = (color: Color) => string; // consumes and describes the colorsdeclare let f: FruitEater | ColorConsumer;f("orange"); // It works! Returns a 'number | string'.f("apple"); // error - Argument of type '"apple"' 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 中,这些签名的参数会相交在一起以创建一个新的签名。
¥In TypeScript 3.3, the parameters of these signatures are intersected together to create a new signature.
在上面的例子中,参数 fruit
和 color
相交生成一个类型为 Fruit & Color
的新参数。Fruit & Color
实际上与 ("apple" | "orange") & ("red" | "orange")
相同,而 ("apple" | "orange") & ("red" | "orange")
又等价于 ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange")
。每个不可能的交叉都简化为 never
,剩下的 "orange" & "orange"
就是 "orange"
。
¥In the example above, the parameters fruit
and color
are intersected together to a new parameter of type Fruit & Color
.
Fruit & Color
is really the same as ("apple" | "orange") & ("red" | "orange")
which is equivalent to ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange")
.
Each of those impossible intersections reduces to never
, and we’re left with "orange" & "orange"
which is just "orange"
.
警告
¥Caveats
此新行为仅当联合中最多有一种类型具有多个重载,并且最多有一种类型具有泛型签名时才会生效。这意味着 number[] | string[]
上的方法,例如 map
(它是泛型的),仍然无法调用。
¥This new behavior only kicks in when at most one type in the union has multiple overloads, and at most one type in the union has a generic signature.
That means methods on number[] | string[]
like map
(which is generic) still won’t be callable.
另一方面,像 forEach
这样的方法现在可以调用,但在 noImplicitAny
下可能会出现一些问题。
¥On the other hand, methods like forEach
will now be callable, but under noImplicitAny
there may be some issues.
ts
interface Dog {kind: "dog";dogProp: any;}interface Cat {kind: "cat";catProp: any;}const catOrDogArray: Dog[] | Cat[] = [];catOrDogArray.forEach(animal => {// ~~~~~~ error!// Parameter 'animal' implicitly has an 'any' type.});
在 TypeScript 3.3 中,这仍然功能更强大,添加显式类型注释即可正常工作。
¥This is still strictly more capable in TypeScript 3.3, and adding an explicit type annotation will work.
ts
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
中复合项目的增量文件监控
¥Incremental file watching for composite projects in --build --watch
TypeScript 3.0 引入了一项用于构建构建的新功能,称为 “复合项目”。这里的部分目标是确保用户可以将大型项目分解成更小的部分,以便快速构建并保留项目结构,同时不影响现有的 TypeScript 体验。得益于复合项目,TypeScript 可以使用 --build
模式仅重新编译项目和依赖集。你可以将其视为优化项目间构建。
¥TypeScript 3.0 introduced a new feature for structuring builds called “composite projects”.
Part of the goal here was to ensure users could break up large projects into smaller parts that build quickly and preserve project structure, without compromising the existing TypeScript experience.
Thanks to composite projects, TypeScript can use --build
mode to recompile only the set of projects and dependencies.
You can think of this as optimizing inter-project builds.
TypeScript 2.7 还通过新的增量 “builder” API 引入了 --watch
模式构建。类似地,此模式的整个思路是仅重新检查并重新触发已更改的文件或其依赖可能影响类型检查的文件。你可以将其视为优化项目内部构建。
¥TypeScript 2.7 also introduced --watch
mode builds via a new incremental “builder” API.
In a similar vein, the entire idea is that this mode only re-checks and re-emits changed files or files whose dependencies might impact type-checking.
You can think of this as optimizing intra-project builds.
在 3.3 之前,使用 --build --watch
构建复合项目实际上并没有使用这种增量文件监视机制。在 --build --watch
模式下更新一个项目将强制完整构建该项目,而不是确定该项目中哪些文件受到影响。
¥Prior to 3.3, building composite projects using --build --watch
actually didn’t use this incremental file watching infrastructure.
An update in one project under --build --watch
mode would force a full build of that project, rather than determining which files within that project were affected.
在 TypeScript 3.3 中,--build
模式的 --watch
标志也利用了增量文件监视。这意味着在 --build --watch
下构建速度会显著加快。在我们的测试中,此功能使构建时间比原始 --build --watch
时间减少了 50% 到 75%。你可以在此处阅读更多有关更改的原始拉取请求 可以查看具体的数值,但我们相信大多数复合项目用户都会在这里看到显著的优势。
¥In TypeScript 3.3, --build
mode’s --watch
flag does leverage incremental file watching as well.
That can mean significantly faster builds under --build --watch
.
In our testing, this functionality has resulted in a reduction of 50% to 75% in build times of the original --build --watch
times.
You can read more on the original pull request for the change to see specific numbers, but we believe most composite project users will see significant wins here.