TypeScript如何编写按键生成对象子集的泛型函数类型
TypeScript 自动生成子Schema类型问题
问题场景
我有一个大型固定内容的键值对对象(命名为schema),该对象为自动生成,无法提前预知具体内容,未来还可能发生变更。
我需要编写一个TypeScript函数,同时满足以下两个要求:
- 声明要从schema中提取的键时,输入键名的过程支持IDE自动补全
- 根据传入的键从原schema生成子schema后,子schema的类型仅允许访问自身包含的键,访问不存在的键需要抛出编译错误
目前我只能单独满足其中一个要求,无法同时实现两个效果。
仅支持自动补全的初始实现
我最初写的版本可以实现键名自动补全,但无法对子schema做严格类型收窄,代码如下:
// 原schema对象 const schema = { key1: 'value1', key2: 'value2', keyX: 'valueX', keyY: 'valueY' }; const makeSubSchema = <Schema extends { [key: string]: string }, Keys extends (keyof Schema)[]>( base: Schema, keys: Keys ) => { // 问题出在这里:Keys[number]类型没有被收窄到仅包含实际传入的键 type SubSchema = Pick<Schema, Keys[number]>; const subSchema = keys.reduce<SubSchema>((acc, key) => { acc[key] = base[key]; return acc; }, {} as SubSchema); return subSchema; }; // 从schema自动生成合法键类型,用于约束键数组 type ValidKey = keyof typeof schema; // 声明键数组为ValidKey[]类型,输入值时可以获得自动补全 const mykeys: ValidKey[] = ['keyX', 'keyY']; const myschema = makeSubSchema(schema, mykeys); // 正常:keyX在传入的键列表中 console.log('keyX', myschema.keyX); // 预期报错:key1不在传入的键列表中,但当前版本不会触发编译错误 console.log('key1', myschema.key1);
这个版本的问题是:访问myschema.key1这类未传入的键时不会报错,TypeScript会判定原schema的所有键都是子schema的合法属性。
仅支持类型收窄的调整方案
我尝试通过as const修饰键数组来解决类型不收窄的问题:
const mykeys = ['keyX', 'keyY'] as const;
调整后访问myschema.key1确实可以正确抛出编译错误,但在数组中输入键名时会丢失自动补全能力。
目前看来第二种方案更接近正确结果,但我还没找到合适的写法,让传入的键既可以获得自动补全,又能让返回的子schema类型严格收窄到仅包含传入的键。
内容的提问来源于stack exchange,提问作者morhekil
相关产品推荐
相关产品推荐

