如何在TypeScript中获取联合类型的兼容公共属性?
TypeScript中获取联合类型的兼容公共属性
核心需求
需要实现类型工具CommonKeys<T>,提取联合类型T中满足以下条件的属性键:
- 键名存在于联合的所有成员类型中;
- 存在有效值可以同时赋值给该键在所有联合成员中的类型(即该键的类型交叉不为
never)。
例如:
type TestUnion = {a: number, b: number, c: string} | {a: number, b: string}; type OnlyA = CommonKeys<TestUnion>; // 期望OnlyA的类型为 "a"(仅a属性的类型在所有成员中兼容,b的类型交叉为number & string = never,无有效值)
更广泛场景:判别式联合的属性更新
基于上述核心需求,希望实现一个函数,根据判别式联合的判别字段,动态限制可更新的属性范围:判别字段的范围越小(越具体),可更新的属性越多。
示例代码:
type Foo = {kind: "foo", id: `foo_${string}`, name: string, age: number} type Bar = {kind: "bar", id: `bar_${string}`, name: string, height: number} type Anyone = Foo | Bar // 期望CommonProps<T>提取T的兼容公共属性,再用Partial包装 function updateSomeone<T extends Anyone["kind"]>(kind: T, patch: Partial<CommonProps<Extract<Anyone, {kind: T}>>>) {} function outer(foo: Foo) { // 已知为Foo类型,允许更新所有属性 updateSomeone(foo.kind, {id: "foo_2", name: "test", age: 45}) } function outer2(fooOrBar: Foo | Bar) { // @ts-expect-error id不允许:没有值能同时满足Foo["id"]和Bar["id"]的类型要求 updateSomeone(fooOrBar.kind, {name: "test", id: "foo_2"}) }
解决方案
实现CommonKeys和CommonProps类型工具
// 获取联合类型中所有成员共有的键名 type SharedKeys<T> = keyof T; // 筛选出键名对应的属性类型交叉不为never的兼容公共键 type CommonKeys<T> = { [K in SharedKeys<T>]: // 提取联合中所有成员的K属性类型,取交叉 (T extends { [key in K]: infer U } ? U : never) extends never ? never : K; }[SharedKeys<T>]; // 提取联合类型的兼容公共属性 type CommonProps<T> = Pick<T, CommonKeys<T>>;
验证效果
- 核心需求示例:
type TestUnion = {a: number, b: number, c: string} | {a: number, b: string}; type OnlyA = CommonKeys<TestUnion>; // 类型为 "a",符合预期
- 判别式联合场景:
- 当调用
updateSomeone("foo", ...)时,Extract<Anyone, {kind: "foo"}>为Foo,CommonProps<Foo>即Foo本身,因此Partial<Foo>允许更新所有属性; - 当调用
updateSomeone(fooOrBar.kind, ...)时,Extract<Anyone, {kind: T}>为Foo | Bar,CommonKeys<Foo | Bar>仅保留"name"(id的类型交叉为never,kind的类型交叉也为never),因此patch仅允许传入name属性,传入id会触发TypeScript错误,符合预期。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

