对象联合类型:如何筛选指定键?
问题描述
我定义了如下对象联合类型:
type Runner = | {company: "Apple", name: "tests", payload: number} | {company: "Apple", name: "cleanup", payload: string} | {company: "Google", name: "tests", payload: number};
我需要定义一个函数,接收该联合类型但只保留指定键(此处为company和name),同时必须保留原联合类型的约束:
- 当
company为"Apple"时,name可以是"tests"或"cleanup" - 当
company为"Google"时,name只能是"tests"
直接使用Pick<Runner, "company" | "name">会丢失联合约束,它会生成一个包含所有可能值的交叉类型,而不是保留原有的联合成员结构。我需要一个类似PickKeys<Runner, "company" | "name">的类型,让它等价于以下函数参数的类型:
function run( runner: | {company: "Apple", name: "tests"} | {company: "Apple", name: "cleanup"} | {company: "Google", name: "tests"} ) {}
解决方案
可以利用TypeScript的分布式条件类型特性,定义一个对联合类型中每个成员单独执行Pick操作的工具类型:
type PickKeys<T, K extends keyof T> = T extends unknown ? Pick<T, K> : never;
然后就可以用这个类型来实现需求:
type RunnerPick = PickKeys<Runner, "company" | "name">; // 验证一下,这个类型等价于我们需要的联合类型 function run(runner: RunnerPick) {} // 符合约束的参数可以正常通过 run({ company: "Apple", name: "tests" }); run({ company: "Apple", name: "cleanup" }); run({ company: "Google", name: "tests" }); // 不符合约束的参数会触发类型错误 run({ company: "Google", name: "cleanup" }); // 类型错误,符合预期
原理说明
当T是联合类型时,T extends unknown ? Pick<T, K> : never会自动将联合类型拆分成单个成员,对每个成员单独应用Pick<T, K>,最后再把结果重新组合成联合类型。这种分布式条件类型的特性,专门用来处理联合类型的逐个成员操作,完美解决了直接使用Pick丢失联合约束的问题。
内容的提问来源于stack exchange,提问作者Myzel394
相关产品推荐
相关产品推荐

