satisfies 和 as const 有什么区别?它们如何配合使用?
简化版
as const 用来把值尽量收窄成只读字面量类型;satisfies 用来检查一个值是否满足某个类型,同时尽量保留值自身推断出的精确类型。两者常配合配置对象和常量表使用。
详细版
示例:
const routes = {
home: '/',
user: '/user/:id',
} as const satisfies Record<string, string>;
as const 保留 '/'、'/user/:id' 这样的字面量。
satisfies Record<string, string> 检查所有 value 都是 string。
它和 as Type 不同,satisfies 不会强行把表达式改成目标类型视角。
完整版教学
一、as const 负责收窄字面量
默认情况下,TypeScript 会把很多对象属性推断得更宽。
例如字符串属性会推断成 string,而不是具体的字面量。
as const 会让值尽量保持字面量,并把对象属性变成只读。
const config1 = { mode: 'dark' };
// mode: string
const config2 = { mode: 'dark' } as const;
// readonly mode: 'dark'
这个差异很关键。 如果后续要从常量对象推导联合类型,必须尽量保留字面量信息。
二、satisfies 负责校验形状但保留推断
类型注解会把变量放到目标类型视角下。
satisfies 则是检查表达式满足某类型,同时保留表达式自身更精确的类型。
这非常适合配置对象。
type Theme = Record<string, { color: string }>;
const theme = {
primary: { color: '#09f' },
danger: { color: '#f43' },
} satisfies Theme;
如果写成 const theme: Theme = ...,key 可能被看成宽泛的 string。
使用 satisfies 后,primary、danger 这些具体 key 更容易保留下来。
三、它和 as 类型断言不是一回事
as Type 是类型断言,偏向告诉编译器“相信我”。
如果断言过宽,可能掩盖错误。
satisfies 是检查,值不满足目标类型时会报错。
type Options = { timeout: number };
const a = { timeout: '3000' } as unknown as Options; // 可能绕过
const b = { timeout: '3000' } satisfies Options; // 报错
| 写法 | 作用 | 是否保留精确推断 | 风险 |
|---|---|---|---|
: Type | 标注变量类型 | 可能变宽 | 中 |
as Type | 类型断言 | 取决于断言 | 高 |
satisfies Type | 校验满足类型 | 通常保留 | 低 |
这也是 satisfies 高频的原因:它比断言更安全。
四、as const 和 satisfies 配合常量表
前端经常维护路由、权限、事件名、主题 token 等常量表。 我们既希望值保持字面量,又希望整体结构被检查。 这时可以组合使用。
const EVENTS = {
Login: 'user_login',
Logout: 'user_logout',
} as const satisfies Record<string, string>;
type EventName = typeof EVENTS[keyof typeof EVENTS];
// 'user_login' | 'user_logout'
流程如下:
对象字面量
-> as const 收窄 key/value 和 readonly
-> satisfies 检查结构
-> typeof 推导联合类型
这套组合非常适合替代部分 enum 场景。
五、satisfies 对额外属性检查很有帮助
配置对象里拼错字段是常见问题。
satisfies 能在对象创建处检查结构。
同时又保留每个字段的具体推断,方便后续精确使用。
type RouteConfig = {
path: string;
auth?: boolean;
};
const routes = {
home: { path: '/', auth: false },
admin: { path: '/admin', auth: true },
} satisfies Record<string, RouteConfig>;
如果把 path 写成 paht,会直接报错。
这比在使用处才发现 undefined 更早。
六、注意 satisfies 不会改变运行时值
satisfies 是 TypeScript 类型运算。
它不会生成校验代码,也不会在运行时验证接口数据。
如果数据来自用户输入或接口响应,仍然需要运行时校验库。
const config = {
timeout: 3000,
} satisfies { timeout: number };
记忆钩子:
as const管“推得窄”,satisfies管“验得准”,两者都不管运行时校验。
数字例子里 3000 可以被保留为字面量,也可以被结构检查为 number。
但运行时传进来的 "3000" 不会因为 satisfies 自动变成数字。
七、常见误区与追问
- 误区:
satisfies等同于as断言。satisfies会做满足性检查,断言更像强行告诉编译器。 - 误区:
as const只是让对象不能修改。 它还会保留字面量类型,是推导联合类型的关键。 - 误区:
satisfies会生成运行时校验。 它只存在于类型检查阶段,不生成校验逻辑。 - 追问:为什么不用
: Record<string,string>? 类型注解可能让具体 key/value 变宽,satisfies更容易保留精确推断。 - 追问:两者组合顺序常怎么写? 常见是对象后接
as const satisfies SomeType。 - 追问:适合什么工程场景? 路由表、权限表、事件名、设计 token、接口字段映射等配置常量。
八、加强记忆
as const 和 satisfies 不是竞争关系:前者收窄值,后者检查形状。回答时用常量表例子说明:既保留 'user_login' 这种字面量,又检查所有值都是 string,最后再强调它们都不做运行时校验。