在 TypeScript 中,若想实现字面量类型窄化或深层不可变,优先选 as const;若仅需限制属性重新赋值,使用 readonly 修饰符即可。
先说结论:as const 侧重于值类型的字面量推断与深层冻结,readonly 侧重于对象属性的赋值权限控制。
- 适合:需要数组元素或对象属性值为具体字面量类型(如 'red' 而非 string)时使用 as const。
- 重点看:readonly 默认只保护当前层级,嵌套对象内部属性仍可能被修改。
- 别忽略:as const 会递归添加 readonly,导致整个结构无法变更,适合配置常量。
核心用法与场景
根据你需要保护的粒度选择语法:
// 场景 1:只需防止属性被重新赋值
interface User { readonly id: string; }// 场景 2:需要字面量类型 + 深层不可变
const config = { db: { host: "localhost" } } as const;1. 检查数组类型推断:如果直接定义数组,类型通常是宽泛的 number[] 或 string[]。若需要元素类型为字面量,需添加 as const。
const colors = ["red", "green"] as const;
// 类型推断为:readonly ["red", "green"]2. 检查嵌套对象可变性:如果配置对象有多层结构,使用 readonly 修饰符可能无法保护内层属性。
interface Config { readonly db: { host: string; }; }
const config: Config = { db: { host: "localhost" } };
config.db.host = "127.0.0.1"; // ✅ 允许修改嵌套属性3. 应用深层冻结:改用 as const 可锁死所有层级。
const config = { db: { host: "localhost" } } as const;
config.db.host = "127.0.0.1"; // ❌ 编译错误原理简述
两者在类型系统层面的根本定位不同。readonly 是属性访问修饰符,本质是对属性访问权限的标记,类似于 public 或 private,它仅限制该属性不可被重新赋值,但不改变类型本身的推断逻辑。而 as const 是字面量类型断言,强制 TypeScript 将值的类型推断为最精确的字面量类型,并递归添加 readonly 修饰。
在线验证与测试
除了本地 IDE 悬浮查看类型外,建议使用 TypeScript Playground 进行在线交互验证,确保行为符合预期。
验证步骤:
- 访问 TypeScript Playground。
- 将上述代码片段粘贴到编辑器中。
- 观察左侧类型提示,或尝试修改属性查看报错信息。
若显示为字面量联合类型(如 "red" | "green")或包含 readonly 标记的元组,说明 as const 生效。尝试修改属性或数组 push 操作,若编辑器报错提示“无法分配到只读属性”或“方法不存在”,则保护机制已生效。
常见坑
- readonly 的局限性:仅作用于当前层级,嵌套对象的属性默认仍可变,不要误以为加了 readonly 就万事大吉。
- 数组方法丢失:使用 as const 后的数组变为只读元组,push、splice 等修改方法将不可用,编译时会报错。
- 类型过窄:as const 会将类型锁死为字面量,若后续需要作为普通 string 或 number 使用,可能需要额外的类型转换。
参考来源
- TypeScript 官方文档 - Const Assertions
原文链接:https://www.zjcp.cc/ask/11040.html
