TypeScript 3.5

速度提升

TypeScript 3.5 在类型检查和增量构建方面引入了多项优化。

类型检查速度提升

相比 TypeScript 3.4,TypeScript 3.5 在类型检查效率上包含了一些优化。这些改进在编辑器场景中尤为明显,因为类型检查驱动了代码补全列表等操作。

--incremental 改进

TypeScript 3.5 改进了 3.4 的 incremental 构建模式,通过保存关于全局状态是如何计算的信息——例如编译器设置、为什么查找文件、在何处找到文件等。在涉及数百个使用 TypeScript 项目引用的 --build 模式的项目中,我们发现与 TypeScript 3.4 相比,重建时间最多可减少 68%

更多详情,请参见以下 pull request:

Omit 辅助类型

TypeScript 3.5 引入了新的 Omit 辅助类型,它通过从原始类型中删除某些属性来创建一个新类型。

ts
type Person = {
name: string;
age: number;
location: string;
};
type QuantumPerson = Omit<Person, "location">;
// equivalent to
type QuantumPerson = {
name: string;
age: number;
};

这里我们能够使用 Omit 辅助类型复制 Person 的所有属性,除了 location

更多详情,请参见 GitHub 上添加 Omit 的 pull request,以及对象剩余部分使用 Omit 的变更

联合类型中改进的多余属性检查

在 TypeScript 3.4 及更早版本中,某些多余属性在不应该被允许的情况下被允许了。例如,即使 name 属性在 PointLabel 之间类型不匹配,TypeScript 3.4 仍允许在对象字面量中使用错误的 name 属性。

ts
type Point = {
x: number;
y: number;
};
type Label = {
name: string;
};
const thing: Point | Label = {
x: 0,
y: 0,
name: true // uh-oh!
};

此前,非区分联合类型不会对其成员进行任何多余属性检查,结果导致类型错误的 name 属性被漏掉了。

在 TypeScript 3.5 中,类型检查器至少会验证所有提供的属性是否属于某个联合成员并且具有相应的类型,这意味着上述示例现在会正确报错。

请注意,只要属性类型有效,部分重叠仍然是被允许的。

ts
const pl: Point | Label = {
x: 0,
y: 0,
name: "origin" // okay
};

--allowUmdGlobalAccess 标志

在 TypeScript 3.5 中,你现在可以引用 UMD 全局声明,例如:

export as namespace foo;

从任何地方(甚至是模块中)引用,使用新的 allowUmdGlobalAccess 标志。

此模式增加了混用第三方库方式的灵活性,即使在模块内也可以使用库声明的全局变量。

更多详情,请参见 GitHub 上的 pull request

更智能的联合类型检查

在 TypeScript 3.4 及更早版本中,以下示例会失败:

ts
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 的每个组成部分都有一个专门为 truefalsedone 属性。这就是我们所说的每个组成类型被独立检查的意思:TypeScript 不会只是将每个属性合并在一起看看 S 是否可以赋值给它。如果这样做了,一些糟糕的代码可能会漏过,如下所示:

ts
interface Foo {
kind: "foo";
value: string;
}
interface Bar {
kind: "bar";
value: number;
}
function doSomething(x: Foo | Bar) {
if (x.kind === "foo") {
x.value.toLowerCase();
}
}
// uh-oh - luckily TypeScript errors here!
doSomething({
kind: "foo",
value: 123
});

然而,对于最初的例子来说,这有点太严格了。如果你计算 S 的任何可能值的精确类型,实际上你会发现它与 T 中的类型完全匹配。

在 TypeScript 3.5 中,当赋值给带有区分属性的类型(如 T 中的类型)时,语言确实会进一步将 S 之类的类型分解为每个可能的具体类型的联合。在这种情况下,由于 booleantruefalse 的联合,S 将被视为 { done: false, value: number }{ done: true, value: number } 的联合。

更多详情,你可以参见 GitHub 上的原始 pull request

从泛型构造函数进行高阶类型推断

在 TypeScript 3.4 中,我们改进了当泛型函数返回函数时(如下所示)的推断:

ts
function compose<T, U, V>(f: (x: T) => U, g: (y: U) => V): (x: T) => V {
return x => g(f(x));
}

将其他泛型函数作为参数时,如下所示:

ts
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 将此行为推广到构造函数上。

ts
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); // has type '<T>(x: T) => Bag<Box<T>>'
let a = f(1024); // has type 'Bag<Box<number>>'

除了上述组合模式外,对泛型构造函数的这种新推断意味着在某些 UI 库(如 React)中操作类组件的函数,可以更正确地操作泛型类组件。

ts
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>> {}
// type is 'new <T>(props: NestedProps<T>) => Component<NestedProps<T>>'
const GenericComponent2 = myHoc(GenericComponent);

要了解更多信息,请查看 GitHub 上的原始 pull request

TypeScript 文档是一个开源项目。欢迎通过提交 Pull Request 来帮助我们改进这些页面 ❤

此页面的贡献者
DRDaniel Rosenwasser (51)
OTOrta Therox (11)
EIEugene Ilyin (1)
JBJack Bates (1)
1+

最后更新:2026 年 3 月 27 日