TypeScript:如何从多对象中按值类型获取所有属性键(非仅交集键)
问题描述
我有一个包含多个子对象(foo、bar、baz)的对象,这些子对象各自拥有不同数据类型的属性。我需要创建一个类型TValueObject,包含所有值类型为对象的属性键,即TValueObject应等于"clientId" | "apiKey" | "oauthToken" | "companyId",但目前仅得到所有对象的交集键"clientId"。
代码示例
源对象定义
const apiToken = { foo: { clientId: { enTitle: 'Client ID', value: '' }, apiKey: { enTitle: 'Api Key', value: '' }, enTitle: 'Foo', isOpen: false, }, bar: { apiKey: { enTitle: 'Api Key', value: '' }, clientId: { enTitle: 'Client ID', value: '' }, enTitle: 'Bar', isOpen: false, }, baz: { oauthToken: { enTitle: 'OAuth token', value: '' }, companyId: { enTitle: 'Company ID', value: '' }, clientId: { enTitle: 'Client ID', value: '' }, enTitle: 'Baz', isOpen: false, }, };
按值类型筛选属性的映射类型
type PickByValue<T, ValueType> = Pick< T, { [Key in keyof T]-?: T[Key] extends ValueType ? Key : never; }[keyof T] >;
当前不符合预期的类型定义
type TKey = keyof typeof apiToken; type TValueObject = keyof PickByValue<typeof apiToken[TKey], object>;
问题原因
typeof apiToken[TKey]是foo、bar、baz三个子对象的联合类型。当对联合类型应用PickByValue时,TypeScript会对联合类型的每个成员分别处理,但keyof (A | B | C)最终会解析为三个子对象键的交集(即所有子对象共有的键),所以最终只得到了三个子对象都有的clientId。
解决方案
要获取所有子对象中值为对象类型的键的联合类型,需要通过分布式条件类型遍历每个子对象,分别筛选后再合并结果:
直接修改TValueObject定义
type TValueObject = keyof typeof apiToken extends infer K ? K extends keyof typeof apiToken ? keyof PickByValue<typeof apiToken[K], object> : never : never;
通用工具类型(可复用)
如果需要多次使用这种逻辑,可以封装成通用类型:
// 从对象的所有子对象中筛选值为指定类型的键的联合类型 type PickByValueFromUnion<T extends Record<string, any>, ValueType> = keyof T extends infer K ? K extends keyof T ? keyof PickByValue<T[K], ValueType> : never : never; // 使用通用类型定义TValueObject type TValueObject = PickByValueFromUnion<typeof apiToken, object>;
此时TValueObject的类型会正确解析为:"clientId" | "apiKey" | "oauthToken" | "companyId"
内容的提问来源于stack exchange,提问作者Иннокентий Цетуев
相关产品推荐
相关产品推荐

