TypeScript 3.5

速度提升

🌐 Speed improvements

TypeScript 3.5 针对类型检查和增量构建引入了几项优化。

🌐 TypeScript 3.5 introduces several optimizations around type-checking and incremental builds.

类型检查加速

🌐 Type-checking speed-ups

TypeScript 3.5 在类型检查方面比 TypeScript 3.4 有一些优化,使类型检查更高效。这些改进在编辑器场景中表现得尤为明显,例如当类型检查驱动代码补全列表等操作时。

🌐 TypeScript 3.5 contains certain optimizations over TypeScript 3.4 for type-checking more efficiently. These improvements are significantly more pronounced in editor scenarios where type-checking drives operations like code completion lists.

--incremental 改进

🌐 --incremental improvements

TypeScript 3.5 在 3.4 的 incremental 构建模式基础上有所改进,通过保存有关世界状态如何计算的信息——编译器设置、文件查询原因、文件位置等。在涉及数百个使用 TypeScript 项目引用的 --build 模式的项目场景中,我们发现,相比 TypeScript 3.4,重建所需时间最多可以减少 68%

🌐 TypeScript 3.5 improves on 3.4’s incremental build mode, by saving information about how the state of the world was calculated - compiler settings, why files were looked up, where files were found, etc. In scenarios involving hundreds of projects using TypeScript’s project references in --build mode, we’ve found that the amount of time rebuilding can be reduced by as much as 68% compared to TypeScript 3.4!

更多详情,请参阅拉取请求

🌐 For more details, you can see the pull requests to

Omit 辅助类型

🌐 The Omit helper type

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

🌐 TypeScript 3.5 introduces the new Omit helper type, which creates a new type with some properties dropped from the original.

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

🌐 Here we were able to copy over all the properties of Person except for location using the Omit helper.

有关更多详情,请参见 GitHub 上关于添加 Omit 的拉取请求,以及 使用 Omit 来处理对象剩余属性的修改

🌐 For more details, see the pull request on GitHub to add Omit, as well as the change to use Omit for object rest.

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

🌐 Improved excess property checks in union types

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

🌐 In TypeScript 3.4 and earlier, certain excess properties were allowed in situations where they really shouldn’t have been. For instance, TypeScript 3.4 permitted the incorrect name property in the object literal even though its types don’t match between Point and Label.

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

以前,对于非区分联合类型,其成员不会进行任何多余属性检查,因此错误类型的 name 属性就会被遗漏。

🌐 Previously, a non-discriminated union wouldn’t have any excess property checking done on its members, and as a result, the incorrectly typed name property slipped by.

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

🌐 In TypeScript 3.5, the type-checker at least verifies that all the provided properties belong to some union member and have the appropriate type, meaning that the sample above correctly issues an error.

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

🌐 Note that partial overlap is still permitted as long as the property types are valid.

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

--allowUmdGlobalAccess 标志

🌐 The --allowUmdGlobalAccess flag

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

🌐 In TypeScript 3.5, you can now reference UMD global declarations like

export as namespace foo;

即使是模块,也可以使用新的 allowUmdGlobalAccess 标志从任何地方进行操作。

🌐 from anywhere - even modules - using the new allowUmdGlobalAccess flag.

此模式为混合和匹配第三方库的方式增加了灵活性,库声明的全局变量始终可以被使用,即使在模块内部也可以。

🌐 This mode adds flexibility for mixing and matching the way 3rd party libraries, where globals that libraries declare can always be consumed, even from within modules.

欲了解更多详情,请参阅 GitHub 上的 拉取请求

🌐 For more details, see the pull request on GitHub.

更智能的联合类型检查

🌐 Smarter union type checking

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

🌐 In TypeScript 3.4 and prior, the following example would fail:

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 是否可以赋值给它。 如果是这样,一些不好的代码可能会通过,例如下面这样:

🌐 That’s because S isn’t assignable to { done: false, value: number } nor { done: true, value: number }. Why? Because the done property in S isn’t specific enough - it’s boolean whereas each constituent of T has a done property that’s specifically true or false. That’s what we meant by each constituent type being checked in isolation: TypeScript doesn’t just union each property together and see if S is assignable to that. If it did, some bad code could get through like the following:

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 中的类型完全匹配。

🌐 However, this was a bit overly strict for the original example. If you figure out the precise type of any possible value of S, you can actually see that it matches the types in T exactly.

在 TypeScript 3.5 中,当分配给具有判别属性的类型(如 T)时,语言实际上会进一步将像 S 这样的类型分解为每一个可能的成员类型的联合。 在这种情况下,由于 booleantruefalse 的联合,S 将被视为 { done: false, value: number }{ done: true, value: number } 的联合。

🌐 In TypeScript 3.5, when assigning to types with discriminant properties like in T, the language actually will go further and decompose types like S into a union of every possible inhabitant type. In this case, since boolean is a union of true and false, S will be viewed as a union of { done: false, value: number } and { done: true, value: number }.

欲了解更多详情,你可以查看 GitHub 上的原始拉取请求

🌐 For more details, you can see the original pull request on GitHub.

泛型构造函数的高阶类型推断

🌐 Higher order type inference from generic constructors

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

🌐 In TypeScript 3.4, we improved inference for when generic functions that return functions like so:

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

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

🌐 took other generic functions as arguments, like so:

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);

与旧版本语言会推断出的相对无用的类型 (x: {}) => Box<{}[]> 不同,TypeScript 3.4 的推断允许 newFn 是泛型。它的新类型是 <T>(x: T) => Box<T[]>

🌐 Instead of a relatively useless type like (x: {}) => Box<{}[]>, which older versions of the language would infer, TypeScript 3.4’s inference allows newFn to be generic. Its new type is <T>(x: T) => Box<T[]>.

TypeScript 3.5 将此行为推广到构造函数。

🌐 TypeScript 3.5 generalizes this behavior to work on constructor functions as well.

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)中对类组件进行操作的函数可以更正确地对泛型类组件进行操作。

🌐 In addition to compositional patterns like the above, this new inference on generic constructors means that functions that operate on class components in certain UI libraries like React can more correctly operate on generic class components.

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 上的原始拉取请求

🌐 To learn more, check out the original pull request on GitHub.