第一次看到 satisfies 时,我觉得它和 as、类型注解差不多,都是在对象后面加一点类型信息。真正开始整理路由配置和主题表之后,才发现它的位置很特别:TypeScript 会检查这个值符合目标类型,同时保留值本身更具体的推断。

普通类型注解有时太宽

假设我们有一个颜色表,键只能是 primarydanger,值可以是字符串或 RGB 数组。直接把变量标成 Record<Color, string | number[]> 没有问题,但取出 palette.primary 时,编辑器只知道它是联合类型,字符串方法就需要额外判断。

type Color = "primary" | "danger";

const palette = {
  primary: "#245d75",
  danger: [232, 93, 63],
} satisfies Record<Color, string | number[]>;

palette.primary.toUpperCase(); // 保留为 string
palette.danger.map(String);     // 保留为 number[]

如果键拼错,或者漏掉必需的键,检查仍然会报错。我们同时拿到了约束和精确推断,这正是配置对象最需要的组合。

我会在这些地方使用

第一类是路由、菜单、权限这类静态映射。对象的形状需要被统一约束,但每个成员又有自己的字面量信息。第二类是传给第三方库的配置:用 satisfies SomeConfig 能提前发现字段拼错,又不会把整个对象都扩宽成库定义。

它也很适合配合 as const,不过顺序和目标要想清楚。as const 让值变成只读字面量,satisfies 负责检查约束。若后续代码需要修改数组,就不要为了“类型更精确”随手加只读。

简单判断:如果你正在声明一个值,但更关心“它符合某个结构吗”,而不是“把它的类型强制变成某个结构”,可以考虑 satisfies

它不会帮你转换数据

satisfies 只存在于类型检查阶段,不会验证接口返回值,也不会在运行时补默认值。外部 JSON 即使写了 satisfies,不可信的数据仍然要用校验库或手写检查处理。

它也不是为了消灭类型注解。函数参数、公开返回值和类成员仍然需要清楚的类型边界。对我来说,它主要让“静态配置对象”更舒服:错误能被发现,编辑器也知道每个值究竟是什么。一个小语法,解决的正好是日常里反复出现的小问题。

← 上一篇下一篇:容器查询 →