TypeScript 4.9 发布!重点新特性解读 ~

2023-01-09 19:13:51 浏览数 (1)

大家好,我是 ConardLi。

11 月 1 日,TypeScript 4.9 发布了候选版本 (RC),直到稳定版发布基本上不会有太大变化了,本次带来的更新还是挺有意思的,下面我就跟大家来一起看一下~

新的 satisfies 操作符

在使用 TypeScript 类型推断的时候,有很多情况下会让我们面临两难的选择:我们即希望确保某些表达式能够匹配某些类型,但也希望保留这个表达式的特定类型用来类型推断。

比如下面的例子,我们定义了一个颜色选择对象:

代码语言:javascript复制
const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

因为每个属性都被赋予了默认值,ts 会自动帮我们自动推导 palette 的属性类型,所以我们可以直接调用它们的方法:

代码语言:javascript复制
// red 被推断为 number[] 类型
const a = palette.red.at(0);
// green 被推断为 string 类型
const b = palette.green.toUpperCase();

因为颜色都是固定的,我们想让我们的 palette 对象拥有特定的几个属性,来避免我们写出一些错别字:

代码语言:javascript复制
const palette = {
    // 错别字:rad -> red
    rad: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

所以我们可能会为 palette 定义一个类型,这样错别字就会被检测出来了:

代码语言:javascript复制
type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
    rad: [255, 0, 0],
//  ~~~~ The typo is now correctly detected
    green: "#00ff00",
    blue: [0, 0, 255]
};

但是这时候我们再调用 palette.red 的方法,你会发现 TS 的类型推断会出错:

代码语言:javascript复制
type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

// 'palette.red' "could" 的类型是 string | RGB ,所以它不一定存在 at 方法
const a = palette.red.at(0);

这就让我们陷入了两难的境地,我们用更严格了类型约束了写出 bug 的可能性,但是却失去了类型推断的能力。

satisfies 关键字就是用来解决这个问题的,它既能让我们验证表达式的类型是否与某个类型匹配,也可以保留基于值进行类型推断的能力:

代码语言:javascript复制
type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette = {
    rad: [255, 0, 0],
    // 可以捕获到错别字 rad
    green: "#00ff00",
    blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;

// 都可以调用
const a = palette.red.at(0);
const b = palette.green.toUpperCase();

in 操作符类型收窄优化

在日常开发中,我们经常需要处理一些在运行时不完全确定的值,比如我们现在有下面两个类型:

代码语言:javascript复制
interface Duck {
  quack(): string;
}

interface Cat {
  miao(): string;
}

在实际使用过程中,TS 不能确定 value 是否是上面中哪一个类型,所以会抛出错误:

代码语言:javascript复制
function main(value: Duck | Cat) {
  if (value.quack) { // roperty 'quack' does not exist on type 'Duck | Cat'.
    return value.quack;
  }
}

我们可能会使用 in 这样的关键字来实现简单的类型收窄:

代码语言:javascript复制
function main(value: Duck | Cat) {
  if ('quack' in value) { 
    return value.quack;
  }
}

也可以实现一个更通用的类型守卫,可以参考我这篇文章:什么是鸭子

0 人点赞