一、为什么要 "as const"
1、默认情况下,TS把字面量推断成"宽类型"
arduino
const a = 'foo' // 类型是 string,不是 'foo'
于是你写 'foo' | 'bar' 时, 一旦拼错成 'fooo', TS不会拦你。
2、加上 as const ,TS会把它当成"不可变的精确字面量"
csharp
const a = 'foo' as const // 类型是 'foo',宽不了
数组、对象同理:
csharp
const arr = [1, 2, 3] // number[]
const arr2 = [1, 2, 3] as const // readonly [1, 2, 3] // 元组 + 字面量
二、keyof typeof: 把值世界映射到类型世界
- typeof:能把运行时的值变成类型;
- keyof:能把对象类型变成联合类型
合起来就是:给我一个对象,我立刻推出它所有建的字面量联合。
ini
const obj = {a: 1, b: 2} as const
type keys = keyof typeof obj // 'a' | 'b'
三、组合拳实战:从"一段配置"到"类型+运行时"全打通
需求:做一个下拉框,选项是「所有摄像头名称」,后台接口也只接受这四个字符串;以后加新摄像头,改一处即可。
步骤1:写配置(as const 固化)
css
// camera.ts
export const cameraMap = {
student_closeup: { label: '学生特写', stream: '/stu/close' },
student_full: { label: '学生全景', stream: '/stu/full' },
teacher_closeup: { label: '老师特写', stream: '/tea/close' },
teacher_full: { label: '老师全景', stream: '/tea/full' },
} as const
步骤 2:一次性导出所有要用的类型
typescript
// 从同一份配置推导,零手工维护
export type CameraKey = keyof typeof cameraMap // 'student_closeup' | ...
export type CameraMeta = typeof cameraMap[CameraKey] // 每个 value 的结构
步骤3:组件里随便用
csharp
/* 下拉框当前值,类型是 CameraKey,写错字母会报错 */
const selected = ref<CameraKey>('student_closeup')