问题场景
TS 里有个经典的两难:
需求 :定义一个主题配置对象,color 键必须是预定义的颜色名字符串的子集,但又要保留每个值精确的字面量类型 (方便后续 keyof、模板推导)。
你可能会先想到类型注解:
ts
type Color = 'red' | 'green' | 'blue';
interface Theme { primary: Color; highlight: Color }
const theme: Theme = {
primary: 'red',
highlight: 'green', // ✅ 类型检查生效
};
// ❌ 但类型注解"收窄"了推断:theme.primary 是 Color,不是 'red'
theme.primary // 类型: Color(丢掉了 'red' 这个字面量)
想让 theme.primary 保持 'red' 字面量,又得忍受注解的收窄;不加注解,又丢了"必须是合法颜色"的校验。
原因分析
- 类型注解(
: Theme) :会做结构校验,但变量类型被固定为注解类型 ,丢失了字面量推断('red'被拓宽成Color)。 - 不加注解(
const theme = {...}) :保留完整的字面量类型推断,但没有校验 ,写错值也不报错------primary: 'purple'悄悄通过。
as const 能锁死字面量,但它是断言 (绕过检查),且会让对象变只读,不是为这种场景设计的。
TS 4.9 推出的 satisfies 就是为了同时满足这两个诉求:用 satisfies 做类型校验,同时保留原始推断类型。
解决方案
基本用法
ts
type Color = 'red' | 'green' | 'blue';
interface Theme { primary: Color; highlight: Color }
const theme = {
primary: 'red',
highlight: 'green',
} satisfies Theme; // ✅ 通过校验
现在的效果:
- 校验生效 :
primary: 'purple'→ 报错Type '"purple"' is not assignable to type 'Color'。 - 类型保留 :
theme.primary的类型是'red'(字面量),而不是被拓宽成Color。
常用场景 1:对象里的字面量 + keyof 推导
ts
const routes = {
'/': 'home',
'/about': 'about',
'/contact': 'contact',
} satisfies Record<string, string>;
type RoutePath = keyof typeof routes; // '/' | '/about' | '/contact'
satisfies Record<string, string> 校验了所有值都是 string,同时 typeof routes 仍保留精确的键和值类型,keyof 就能推导出联合路径。
常用场景 2:组件/API 的 props 对象
ts
type ButtonSize = 'sm' | 'md' | 'lg';
const buttonProps = {
size: 'lg',
label: '提交',
} satisfies { size: ButtonSize; label: string };
// size 校验合格,且 buttonProps.size 仍推断为 'lg'
与 as const / 注解对比
| 写法 | 类型校验 | 保留字面量 | 副作用 |
|---|---|---|---|
: Theme 注解 |
✅ | ❌ 拓宽 | 变量类型被固定 |
as const |
❌ 跳过 | ✅ 锁定 | 强制只读 + 绕过检查 |
satisfies |
✅ | ✅ | 无(保留推断) |
satisfies 是只校验、不改变类型,所以它不产生只读副作用,也不会丢失字面量------恰好填补了前两者的空白。
要点总结
satisfies X的意思是"这个值满足 X 的类型要求 ",用于校验 ,而不是声明变量类型。- 它保留原始的字面量推断 :
theme.primary仍是'red',不会被拓宽成Color。 - 适合场景 :既要对对象/值做接口校验,又想在后续用
keyof typeof、模板推导拿到精确字面量类型。 - 不需要"保留字面量只做校验"时,普通类型注解就够;要锁死只读字面量用
as const。 - 需要 TS 4.9+,注意工程 tsconfig / 语言版本。
- 常见组合:
satisfies Record<string, ...>+keyof typeof,是推导路由/映射表类型的神器。
一句话:
satisfies让你"既要又要"------既要类型检查兜底,又要字面量类型不丢失。构建 config、routes、props 这类"值要精确、结构要合法"的对象时,它是首选。