动态导入表达式
¥Dynamic Import Expressions
动态 import
表达式是 ECMAScript 的一项新功能,它允许用户在程序中的任意位置异步请求模块。
¥Dynamic import
expressions are a new feature and part of ECMAScript that allows users to asynchronously request a module at any arbitrary point in your program.
这意味着你可以有条件地、延迟地导入其他模块和库。例如,这里有一个 async
函数,它仅在需要时导入一个工具库:
¥This means that you can conditionally and lazily import other modules and libraries.
For example, here’s an async
function that only imports a utility library when it’s needed:
ts
async function getZipFile(name: string, files: File[]): Promise<File> {const zipUtil = await import("./utils/create-zip-file");const zipContents = await zipUtil.getContentAsBlob(files);return new File(zipContents, name);}
许多打包器都支持根据这些 import
表达式自动拆分输出包,因此请考虑将此新功能与 esnext
模块目标一起使用。
¥Many bundlers have support for automatically splitting output bundles based on these import
expressions, so consider using this new feature with the esnext
module target.
字符串枚举
¥String Enums
TypeScript 2.4 现在允许枚举成员包含字符串初始化器。
¥TypeScript 2.4 now allows enum members to contain string initializers.
ts
enum Colors {Red = "RED",Green = "GREEN",Blue = "BLUE"}
需要注意的是,字符串初始化的枚举无法进行反向映射以获取原始枚举成员名称。换句话说,你不能写 Colors["RED"]
来获取字符串 "Red"
。
¥The caveat is that string-initialized enums can’t be reverse-mapped to get the original enum member name.
In other words, you can’t write Colors["RED"]
to get the string "Red"
.
改进了泛型的推断
¥Improved inference for generics
TypeScript 2.4 对泛型推断的方式进行了一些精彩的改进。
¥TypeScript 2.4 introduces a few wonderful changes around the way generics are inferred.
返回类型作为推断目标
¥Return types as inference targets
首先,TypeScript 现在可以推断调用的返回类型。这可以改善你的体验并捕获错误。现在可以正常工作的部分:
¥For one, TypeScript can now make inferences for the return type of a call. This can improve your experience and catch errors. Something that now works:
ts
function arrayMap<T, U>(f: (x: T) => U): (a: T[]) => U[] {return a => a.map(f);}const lengths: (a: string[]) => number[] = arrayMap(s => s.length);
作为你可能因此发现的新错误的示例:
¥As an example of new errors you might spot as a result:
ts
let x: Promise<string> = new Promise(resolve => {resolve(10);// ~~ Error!});
从上下文类型推断类型参数
¥Type parameter inference from contextual types
在 TypeScript 2.4 之前,以下示例中:
¥Prior to TypeScript 2.4, in the following example
ts
let f: <T>(x: T) => T = y => y;
y
的类型为 any
。这意味着程序会进行类型检查,但从技术上讲,你可以使用 y
做任何事情,例如:
¥y
would have the type any
.
This meant the program would type-check, but you could technically do anything with y
, such as the following:
ts
let f: <T>(x: T) => T = y => y() + y.foo.bar;
最后一个例子实际上并非类型安全的。
¥That last example isn’t actually type-safe.
在 TypeScript 2.4 中,右侧的函数隐式地获得类型参数,并且 y
被推断为具有该类型参数的类型。
¥In TypeScript 2.4, the function on the right side implicitly gains type parameters, and y
is inferred to have the type of that type-parameter.
如果你以类型参数约束不支持的方式使用 y
,则会正确收到错误。在这种情况下,T
的约束条件(隐式)是 {}
,因此最后一个例子将自然失败。
¥If you use y
in a way that the type parameter’s constraint doesn’t support, you’ll correctly get an error.
In this case, the constraint of T
was (implicitly) {}
, so the last example will appropriately fail.
更严格的泛型函数检查
¥Stricter checking for generic functions
TypeScript 现在会在比较两个单签名类型时尝试统一类型参数。因此,在关联两个泛型签名时,你将受到更严格的检查,并且可能会捕获一些错误。
¥TypeScript now tries to unify type parameters when comparing two single-signature types. As a result, you’ll get stricter checks when relating two generic signatures, and may catch some bugs.
ts
type A = <T, U>(x: T, y: U) => [T, U];type B = <S>(x: S, y: S) => [S, S];function f(a: A, b: B) {a = b; // Errorb = a; // Ok}
回调参数的严格逆变
¥Strict contravariance for callback parameters
TypeScript 始终以双变量方式比较参数。造成这种情况的原因有很多,但总的来说,这对我们的用户来说并不是什么大问题,直到我们看到它对 Promise
和 Observable
造成的一些负面影响。
¥TypeScript has always compared parameters in a bivariant way.
There are a number of reasons for this, but by-and-large this was not been a huge issue for our users until we saw some of the adverse effects it had with Promise
s and Observable
s.
TypeScript 2.4 在关联两个回调类型时对此进行了改进。例如:
¥TypeScript 2.4 introduces tightens this up when relating two callback types. For example:
ts
interface Mappable<T> {map<U>(f: (x: T) => U): Mappable<U>;}declare let a: Mappable<number>;declare let b: Mappable<string | number>;a = b;b = a;
在 TypeScript 2.4 之前,此示例会成功。在关联 map
的类型时,TypeScript 会双向关联它们的参数(即 f
的类型)。在关联每个 f
时,TypeScript 也会双向关联这些参数的类型。
¥Prior to TypeScript 2.4, this example would succeed.
When relating the types of map
, TypeScript would bidirectionally relate their parameters (i.e. the type of f
).
When relating each f
, TypeScript would also bidirectionally relate the type of those parameters.
在 TS 2.4 中关联 map
的类型时,该语言会检查每个参数是否为回调类型,如果是,则会确保以与当前关系逆变的方式检查这些参数。
¥When relating the type of map
in TS 2.4, the language will check whether each parameter is a callback type, and if so, it will ensure that those parameters are checked in a contravariant manner with respect to the current relation.
换句话说,TypeScript 现在可以捕获上述错误,这对某些用户来说可能是一个重大更改,但在很大程度上会有所帮助。
¥In other words, TypeScript now catches the above bug, which may be a breaking change for some users, but will largely be helpful.
弱类型检测
¥Weak Type Detection
TypeScript 2.4 引入了 “弱类型” 的概念。任何只包含一组全可选属性的类型都被认为是弱类型。例如,这个 Options
类型是一个弱类型:
¥TypeScript 2.4 introduces the concept of “weak types”.
Any type that contains nothing but a set of all-optional properties is considered to be weak.
For example, this Options
type is a weak type:
ts
interface Options {data?: string;timeout?: number;maxRetries?: number;}
在 TypeScript 2.4 中,当属性没有重叠时,将任何内容赋值给弱类型现在都是错误的。例如:
¥In TypeScript 2.4, it’s now an error to assign anything to a weak type when there’s no overlap in properties. For example:
ts
function sendMessage(options: Options) {// ...}const opts = {payload: "hello world!",retryOnFail: true};// Error!sendMessage(opts);// No overlap between the type of 'opts' and 'Options' itself.// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'.
你可以将其视为 TypeScript “强化” 对这些类型的弱保证,以捕获原本可能隐藏的错误。
¥You can think of this as TypeScript “toughening up” the weak guarantees of these types to catch what would otherwise be silent bugs.
由于这是一项重大变更,你可能需要了解与严格对象字面量检查相同的解决方法:
¥Since this is a breaking change, you may need to know about the workarounds which are the same as those for strict object literal checks:
-
如果属性确实存在,请声明它们。
¥Declare the properties if they really do exist.
-
为弱类型(即
[propName: string]: {}
)添加索引签名。¥Add an index signature to the weak type (i.e.
[propName: string]: {}
). -
使用类型断言(例如
opts as Options
)。¥Use a type assertion (i.e.
opts as Options
).