发布于 2026-01-05 2 阅读
0

如何提升我的 TypeScript 技能 #5:满足运算符

如何提升我的 TypeScript 技能 #5:满足运算符

我将与大家分享一些提升我 TypeScript 技能的技巧!今天我们将学习satisfies4.9 TS 更新中出现的运算符!

一个“无聊的”错误

我们来看一下使用带有多个值的 Record 时常见的错误。

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]
};

const redComponent = palette.red.at(0); // Property 'at' does not exist on type 'string | RGB'.
Enter fullscreen mode Exit fullscreen mode

嗯……这真的很无聊,我们不能直接使用,array methods因为 TypeScript 不知道red属性是 astring还是RGBtype!这是因为我们使用了Record<Colors, string | RGB>.

stringTypeScript 无法确定和之间的正确类型RGB

第一种方法:缩小范围

我们可以缩小类型范围!

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]
};

function setColor(color: RGB | string) {
    if (color instanceof Array) {
      return color.forEach(); // We can use array methods
    } else {
      return color.toUpperCase(); // It's a string ! So we can use String methods
    }
}
Enter fullscreen mode Exit fullscreen mode

这是一个解决方案,但我们需要添加用于输入内容的运行代码。

第二种解决方案:无类型

您可以通过移除类型来解决这个问题。

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

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

const redComponent = palette.red.at(0);
Enter fullscreen mode Exit fullscreen mode

这也是一个“糟糕”的解决方案,为什么呢?因为你没有输入框,所以可能会输入错误的键或者出现拼写错误!

const palette = {
    red: [255, 0, 0],
    green: null, // It should throw error
    bleu: [0, 0, 255] // It should throw error since it's not 'bleu' but 'blue'
};
Enter fullscreen mode Exit fullscreen mode

第三种解决方案:作为常量

简要介绍一下as const`.` : as const`.` 用于阻止对变量的任何编辑,例如 `const` 赋值。这种阻止作用使得 TypeScript 能够通过更多细节来缩小正确类型的范围。

const a: string = 'hello' // is string
const b = 'hello' as const // is 'hello'
Enter fullscreen mode Exit fullscreen mode

我们来试试!

const palette = {
    "red": "yes",
    "green": false,
    "fakeKey": false, // It should throw error
    "bleu": "kinda", It should throw error
} as const;
Enter fullscreen mode Exit fullscreen mode

所以它和旧方案一样,没有严格的类型限制!因此它可能导致错误wrong key或错误misstypo

最后一种解决方案:从基本类型创建特定类型

为了实现正确的缩小范围,您还可sub type以为每个对象创建特定的范围。

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

type One = Record<"red", RGB> & Record<"green" | "blue", string>

const palette: One = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: "#00ff00"
}

palette.red // RGB
palette.blue // string
Enter fullscreen mode Exit fullscreen mode

如果筛选条件正确,那就太好了!但如果你有很多键和值,我得说:Good luck我的朋友。

所以,时候到了……

满意了,我们开始吧

新的满足运算符允许我们验证表达式的类型是否与某种类型匹配,而不会改变该表达式的结果类型。

TypeScript 开发人员经常面临一个两难困境:我们希望确保某个表达式与某个类型匹配,但同时也希望保留该表达式最具体的类型以进行类型推断。

例如,我们可以使用 satifies 来验证 palette 的所有属性是否与 string | number[] 兼容。

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

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

palette.red // RGB !
palette.green // string !
Enter fullscreen mode Exit fullscreen mode

它捕获了所有可能的输入错误。

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    wrongKey: "#00ff00", // Catch Error !
    bleu: [0, 0, 255], // Catch Error !
} satisfies Record<Colors, string | RGB>

palette.green = [0, 0, 255] // ! green is basically string, it cannot be RGB !
Enter fullscreen mode Exit fullscreen mode

我们解决了这个问题!

如果让我对satifies运算符给出一个简短的定义,应该是这样的:

satisfies operator check a type like Record<string, A | B>, and narrow the correct type between A | B for each key

奖励,满足 + 作为常量

您可以添加所有as const与以下组合带来的益处satifies

在这个例子中:

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

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

palette.redRGB,不是[255, 0, 0]。这是正常的,因为我们可以用另一个 RGB 值来编辑 palette.red,例如[255, 255, 255]

如果你需要这个strict value type,你可以使用as const

type Colors = "red" | "green" | "blue";
// We use Readonly utils type for using as const
type RGB = Readonly<[red: number, green: number, blue: number]>

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

palette.red // [255, 0, 0]
palette.red = [255, 255, 0] // throw error since we cannot edit an property that is constant
Enter fullscreen mode Exit fullscreen mode

希望您喜欢这篇文章!

☕️ 您可以支持我的作品🙏

🏃‍♂️ 你可以关注我 👇

🕊 Twitter:https://twitter.com/code__oz

👨‍💻 Github:https://github.com/Code-Oz

🇫🇷🥖 对于法国开发者,您可以查看我的YouTube 频道

您可以收藏这篇文章!

文章来源:https://dev.to/codeoz/how-i-improve-my-skills-in-typescript-5-satisfies-operator-2312