TypeScript 3.5
速度改进
TypeScript 3.5 在类型检查和增量构建方面引入了多项优化。
类型检查加速
TypeScript 3.5 包含了对 TypeScript 3.4 的某些优化,以更高效地进行类型检查。 这些改进在编辑器场景中尤其明显,因为类型检查驱动着代码补全列表等操作。
--incremental 改进
TypeScript 3.5 改进了 3.4 的 incremental 构建模式,通过保存关于世界状态如何计算的信息——编译器设置、文件查找原因、文件查找位置等。 在涉及使用 TypeScript 项目引用的 --build 模式的数百个项目的场景中,我们发现与 TypeScript 3.4 相比,重建时间可减少多达 68%!
有关更多详细信息,你可以查看拉取请求:
Omit 辅助类型
TypeScript 3.5 引入了新的 Omit 辅助类型,它创建一个新类型,从原始类型中删除某些属性。
type Person = {
name: string;
age: number;
location: string;
};
type QuantumPerson = Omit<Person, "location">;
// 等同于
type QuantumPerson = {
name: string;
age: number;
};这里我们使用 Omit 辅助类型复制了 Person 除 location 之外的所有属性。
有关更多详细信息,请查看 GitHub 上添加 Omit 的拉取请求,以及对对象剩余使用 Omit 的更改。
改进联合类型中的多余属性检查
在 TypeScript 3.4 及更早版本中,某些多余属性在不应允许的情况下被允许。 例如,TypeScript 3.4 允许对象字面量中不正确的 name 属性,即使其类型在 Point 和 Label 之间不匹配。
type Point = {
x: number;
y: number;
};
type Label = {
name: string;
};
const thing: Point | Label = {
x: 0,
y: 0,
name: true // 哎呀!
};以前,非可辨识联合不会对其成员进行任何多余属性检查,因此类型错误的 name 属性被遗漏了。
在 TypeScript 3.5 中,类型检查器至少会验证所有提供的属性属于某个联合成员且具有适当的类型,这意味着上面的示例正确报错。
请注意,只要属性类型有效,部分重叠仍然允许。
const pl: Point | Label = {
x: 0,
y: 0,
name: "origin" // 可以
};--allowUmdGlobalAccess 标志
在 TypeScript 3.5 中,你现在可以使用新的 allowUmdGlobalAccess 标志从任何地方——甚至是模块中——引用 UMD 全局声明,如
export as namespace foo;此模式为混合和匹配第三方库的方式增加了灵活性,库声明的全局变量始终可以被消费,即使是在模块内部。
有关更多详细信息,请查看 GitHub 上的拉取请求。
更智能的联合类型检查
在 TypeScript 3.4 及之前,以下示例会失败:
type S = { done: boolean; value: number };
type T = { done: false; value: number } | { done: true; value: number };
declare let source: S;
declare let target: T;
target = source;这是因为 S 不能赋值给 { done: false, value: number } 也不能赋值给 { done: true, value: number }。 为什么? 因为 S 中的 done 属性不够具体——它是 boolean,而 T 的每个组成部分都有一个明确为 true 或 false 的 done 属性。 这就是我们所说的每个组成部分类型被孤立检查的意思:TypeScript 不只是将每个属性联合起来,然后看 S 是否能赋值给该联合。 如果这样做,一些坏代码可能会通过,如下所示:
interface Foo {
kind: "foo";
value: string;
}
interface Bar {
kind: "bar";
value: number;
}
function doSomething(x: Foo | Bar) {
if (x.kind === "foo") {
x.value.toLowerCase();
}
}
// 哎呀 - 幸运的是 TypeScript 在这里报错了!
doSomething({
kind: "foo",
value: 123
});然而,对于原始示例,这有点过于严格了。 如果你计算出 S 任何可能值的精确类型,你实际上可以看到它与 T 中的类型完全匹配。
在 TypeScript 3.5 中,当赋值给像 T 这样具有可辨识属性的类型时,语言实际上会进一步将像 S 这样的类型分解为每个可能存在类型的联合。 在这种情况下,因为 boolean 是 true 和 false 的联合,S 将被视为 { done: false, value: number } 和 { done: true, value: number } 的联合。
有关更多详细信息,你可以查看 GitHub 上的原始拉取请求。
泛型构造器的高阶类型推断
在 TypeScript 3.4 中,我们改进了泛型函数的推断,这些函数返回函数如下:
function compose<T, U, V>(f: (x: T) => U, g: (y: U) => V): (x: T) => V {
return x => g(f(x));
}将其他泛型函数作为参数,如下所示:
function arrayify<T>(x: T): T[] {
return [x];
}
type Box<U> = { value: U };
function boxify<U>(y: U): Box<U> {
return { value: y };
}
let newFn = compose(arrayify, boxify);TypeScript 3.4 的推断允许 newFn 是泛型的,而不是旧版本语言推断的相对无用的类型,如 (x: {}) => Box<{}[]>。 它的新类型是 <T>(x: T) => Box<T[]>。
TypeScript 3.5 将此行为推广到也适用于构造函数。
class Box<T> {
kind: "box";
value: T;
constructor(value: T) {
this.value = value;
}
}
class Bag<U> {
kind: "bag";
value: U;
constructor(value: U) {
this.value = value;
}
}
function composeCtor<T, U, V>(
F: new (x: T) => U,
G: new (y: U) => V
): (x: T) => V {
return x => new G(new F(x));
}
let f = composeCtor(Box, Bag); // 类型为 '<T>(x: T) => Bag<Box<T>>'
let a = f(1024); // 类型为 'Bag<Box<number>>'除了上述的组合模式之外,这种对泛型构造函数的新推断意味着在某些 UI 库(如 React)中操作类组件的函数可以更正确地操作泛型类组件。
type ComponentClass<P> = new (props: P) => Component<P>;
declare class Component<P> {
props: P;
constructor(props: P);
}
declare function myHoc<P>(C: ComponentClass<P>): ComponentClass<P>;
type NestedProps<T> = { foo: number; stuff: T };
declare class GenericComponent<T> extends Component<NestedProps<T>> {}
// 类型是 'new <T>(props: NestedProps<T>) => Component<NestedProps<T>>'
const GenericComponent2 = myHoc(GenericComponent);要了解更多信息,请查看 GitHub 上的原始拉取请求。