如何让TypeScript的keyof支持对象的动态键约束?
问题
我想实现一个从对象中取值的函数,用参数作为对象的键,但发现对象包含动态属性时,keyof无法限制键的范围,反而接受所有字符串。
比如下面的示例,实现了一个对象提取器,允许传入对象的键提取值:
function makeObjectExtractor( keyA: string, ) { const toExtractFrom = { // keyA是动态属性,导致keyof允许任意字符串或数字 [keyA]: 4, keyB: 5 } satisfies Record<string, number>; function getIncrementedVal(param: keyof typeof toExtractFrom) { return toExtractFrom[param] + 1; } return getIncrementedVal; } const extractor = makeObjectExtractor('g'); // 这里应该触发TypeScript错误,但因为keyA是动态属性,并没有报错 extractor('asdfasdf');
我需要让TypeScript识别出仅允许'g'和'keyB'作为合法键。如果把所有键硬编码,keyof就能正确限制范围:
function makeObjectExtractor( ) { const toExtractFrom = { b: 4, keyB: 5 } satisfies Record<string, number>; function getIncrementedVal(param: keyof typeof toExtractFrom) { return toExtractFrom[param] + 1; } return getIncrementedVal; } const extractor = makeObjectExtractor(); // 这里正确触发错误 extractor('asdfasdf'); // 这里不会报错,符合预期 extractor('b');
这种情况下keyof会正确限制为"b" | "keyB",请问如何让keyof支持动态键?
解决方案
要让TypeScript跟踪动态键的具体类型,需要通过泛型约束参数的类型,替代原本宽泛的string类型:
修改后的代码
function makeObjectExtractor<K extends string>( keyA: K, ) { const toExtractFrom = { [keyA]: 4, keyB: 5 } satisfies Record<K | 'keyB', number>; function getIncrementedVal(param: K | 'keyB') { return toExtractFrom[param] + 1; } return getIncrementedVal; } const extractor = makeObjectExtractor('g'); // 正确触发TypeScript错误:类型'"asdfasdf"'的参数不能赋给类型'"g" | "keyB"'的参数 extractor('asdfasdf'); // 正常通过类型检查 extractor('g'); extractor('keyB');
核心逻辑
- 泛型
K extends string会在函数调用时,自动捕获传入keyA的具体字符串字面量(比如'g'),而非宽泛的string类型 - 用
K | 'keyB'明确限定提取函数的合法键范围,替代原本keyof typeof toExtractFrom的宽泛推断 satisfies Record<K | 'keyB', number>确保对象类型符合预期,同时保留具体键的类型信息
内容的提问来源于stack exchange,提问作者Oved D
相关产品推荐
相关产品推荐

