Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

TypeScript 2.4

动态导入表达式

动态 import 表达式是一个新特性,也是 ECMAScript 的一部分,允许用户在程序的任意点异步请求一个模块。

这意味着你可以有条件地、懒加载地导入其他模块和库。 例如,这里有一个 async 函数,只在需要时才导入一个实用工具库:

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 模块目标一起使用。

字符串枚举

TypeScript 2.4 现在允许枚举成员包含字符串初始化器。

ts
enum Colors {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

需要注意的是,使用字符串初始化的枚举无法反向映射以获取原始枚举成员名称。 换句话说,你不能写 Colors["RED"] 来获取字符串 "Red"

泛型的改进推断

TypeScript 2.4 在泛型推断的方式上引入了一些很棒的变化。

返回类型作为推断目标

首先,TypeScript 现在可以对调用的返回类型进行推断。 这可以改善你的体验并捕获错误。 现在可以工作的示例:

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

作为一个你可能因此发现的新错误的例子:

ts
let x: Promise<string> = new Promise(resolve => {
  resolve(10);
  //      ~~ 错误!
});

从上下文类型推断类型参数

在 TypeScript 2.4 之前,在以下示例中

ts
let f: <T>(x: T) => T = y => y;

y 的类型将是 any。 这意味着程序会通过类型检查,但从技术上讲,你可以对 y 做任何事情,例如:

ts
let f: <T>(x: T) => T = y => y() + y.foo.bar;

最后一个例子实际上不是类型安全的。

在 TypeScript 2.4 中,右侧的函数隐式获得类型参数,并且 y 被推断为具有该类型参数的类型。

如果你以类型参数约束不支持的方式使用 y,你将正确地得到一个错误。 在这种情况下,T 的约束是(隐式地){},因此最后一个例子将适当地失败。

对泛型函数的更严格检查

TypeScript 现在在比较两个单签名类型时尝试统一类型参数。 因此,在关联两个泛型签名时,你将获得更严格的检查,并可能捕获一些错误。

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; // 错误
  b = a; // 可以
}

回调参数的严格逆变

TypeScript 一直以来都是双变地比较参数。 这有很多原因,但总的来说,直到我们看到它对 PromiseObservable 的一些不利影响之前,这对我们的用户来说并不是一个大问题。

TypeScript 2.4 在关联两个回调类型时收紧了这一点。例如:

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 也会双向关联那些参数的类型。

在 TS 2.4 中关联 map 的类型时,语言会检查每个参数是否为回调类型,如果是,它将确保这些参数相对于当前关系以逆变的方式进行检查。

换句话说,TypeScript 现在捕获了上述错误,这可能对某些用户来说是破坏性更改,但在很大程度上是有帮助的。

弱类型检测

TypeScript 2.4 引入了“弱类型”的概念。 任何只包含一组全可选属性的类型都被认为是的。 例如,这个 Options 类型是一个弱类型:

ts
interface Options {
  data?: string;
  timeout?: number;
  maxRetries?: number;
}

在 TypeScript 2.4 中,当属性没有重叠时,将任何值赋值给弱类型现在是一个错误。 例如:

ts
function sendMessage(options: Options) {
  // ...
}

const opts = {
  payload: "hello world!",
  retryOnFail: true
};

// 错误!
sendMessage(opts);
// 'opts' 的类型与 'Options' 本身没有重叠。
// 也许我们本意是使用 'data'/'maxRetries' 而不是 'payload'/'retryOnFail'。

你可以认为这是 TypeScript“加强”了这些类型的弱保证,以捕获原本会静默的 bug。

由于这是一个破坏性更改,你可能需要了解解决方法,这些方法与严格对象字面量检查的解决方法相同:

  1. 如果属性确实存在,就声明它们。
  2. 为弱类型添加索引签名(即 [propName: string]: {})。
  3. 使用类型断言(即 opts as Options)。