如何从已类型化的Partial对象提取实际存在的键而非全部允许键
问题描述
我想从对象中提取实际存在的键列表,同时要求这些键必须属于某个指定的允许值集合。目前只能单独实现其中一项:要么提取所有键(包括无效的),要么限制键在允许范围内但提取出所有允许值而非实际存在的键。
示例1:无类型约束时的键提取
不指定键的类型时,能轻松提取键,但会包含无效值:
// 如果不指定键的类型,我可以轻松提取它们。 const workdayAttributesAuto = { Monday: 123, Tuesday: 456, Floofday: -1, // 糟糕,我可以指定一个无效的日期 }; // 现在我可以顺利将它们提取为另一个类型,但这里不仅包含Monday和Tuesday,还混入了不需要的无效值。 export type workdayNamesAuto = keyof typeof workdayAttributesAuto; // --> type workdayNamesAuto = 'Monday' | 'Tuesday' | 'Floofday';
示例2:有类型约束但无法提取实际键
指定类型限制键为允许值后,提取的是所有允许值而非对象中实际存在的键:
type Days = 'Sunday' | 'Monday' | 'Tuesday'; // 仅允许这些键 const workdayAttributes: Partial<Record<Days, number>> = { // 故意省略了Sunday Monday: 123, Tuesday: 456, //Floofday: 0, // 不允许指定无效日期,这很好 }; // 但现在这个类型包含了Sunday,而它并不是对象中的实际键。 export type workdayNames = keyof typeof workdayAttributes; // --> type workdayNames = 'Sunday' | 'Monday' | 'Tuesday';
如何让keyof typeof仅获取对象中实际指定的键,而非所有允许的可能值?
解决方案
可以通过两种方式实现:既限制键的合法范围,又保留对象的字面量类型,从而提取实际存在的键。
方式一:泛型函数约束(兼容所有TS版本)
创建泛型函数约束对象键的范围,同时让TypeScript推导对象的字面量类型:
type Days = 'Sunday' | 'Monday' | 'Tuesday'; // 泛型函数:约束对象的键只能是Days的子集,同时保留字面量类型 const createRestrictedObject = <T extends Partial<Record<Days, number>>>(obj: T) => obj; // 创建受约束的对象,无效键会直接报错 const workdayAttributes = createRestrictedObject({ Monday: 123, Tuesday: 456, // Floofday: -1, // 此处会触发类型错误,不符合Days约束 }); // 提取实际存在的键 export type workdayNames = keyof typeof workdayAttributes; // --> type workdayNames = 'Monday' | 'Tuesday';
方式二:satisfies关键字(TS 4.9+)
用satisfies关键字直接检查对象是否符合指定类型,但不改变对象的字面量类型:
type Days = 'Sunday' | 'Monday' | 'Tuesday'; const workdayAttributes = { Monday: 123, Tuesday: 456, } satisfies Partial<Record<Days, number>>; // 提取实际存在的键 export type workdayNames = keyof typeof workdayAttributes; // --> type workdayNames = 'Monday' | 'Tuesday';
内容的提问来源于stack exchange,提问作者Malvineous
相关产品推荐
相关产品推荐

