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 一直以来都是双变地比较参数。 这有很多原因,但总的来说,直到我们看到它对 Promise 和 Observable 的一些不利影响之前,这对我们的用户来说并不是一个大问题。

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