TypeScript中如何通过keyof typeof获取对象键精确联合类型
问题根源
你当前写法无法得到精确键联合的核心原因是:显式给myConfs标注带字符串索引签名{ [k: string]: (myArg: { name: string }) => string }的类型后,TypeScript会直接将变量类型收窄为这个宽泛的索引类型,丢失对象字面量本身的具体键信息,此时keyof typeof myConfs得到的结果自然是string,无法对赋值做精确校验。
如果直接移除显式类型标注,TS虽然能推导出精确的键字面量联合,但失去了对每个属性对应回调函数的类型约束,两种写法都无法同时满足「约束值类型」和「保留精确键类型」两个需求。
实现方法
TS 4.9+ 推荐方案:使用satisfies运算符
satisfies是TS 4.9版本新增的关键字,作用是校验表达式是否匹配指定类型,但不改变表达式本身的推导类型,完全匹配当前场景的需求:
const myConfs = { 'Hello': ({ name }) => `World from ${name}`, 'Goodbye': ({ name }) => `World from ${name}`, } satisfies { [k: string]: (myArg: { name: string }) => string }; type MyKeys = keyof typeof myConfs; // 推导结果为 "Hello" | "Goodbye" // 此处会按预期抛出类型错误:Type '"hello"' is not assignable to type '"Hello" | "Goodbye"' const key: MyKeys = 'hello';
这个写法的优势:
- 自动校验
myConfs下所有属性的回调是否符合签名要求,如果参数类型、返回值类型写错,TS会直接在对应属性位置抛出错误 - 完全保留对象字面量的键值推导结果,不会把键拓宽为
string类型
低版本兼容方案:泛型辅助函数
如果你的项目TS版本低于4.9,无法使用satisfies,可以通过泛型辅助函数实现相同效果,利用泛型推导保留具体键类型,同时约束值的类型符合要求:
// 定义泛型构造函数 const defineMyConfs = <T extends string>( confs: Record<T, (myArg: { name: string }) => string> ) => confs; const myConfs = defineMyConfs({ 'Hello': ({ name }) => `World from ${name}`, 'Goodbye': ({ name }) => `World from ${name}`, }); type MyKeys = keyof typeof myConfs; // 推导结果为 "Hello" | "Goodbye" // 此处同样会按预期抛出类型错误 const key: MyKeys = 'hello';
内容的提问来源于stack exchange,提问作者Jeggy
相关产品推荐
相关产品推荐

