有两种类型
type A = {
x: number
y: number
}
type B = {
y: number
z: number
}
如何获取具有该类型的公共属性的类型?
type C = Something<T1, T2> // { y: number }
答案 0 :(得分:11)
使用静态keyof
运算符:
type Ka = keyof A // 'x' | 'y'
type Kb = keyof B // 'y' | 'z'
type Kc = Ka & Kb // 'y'
使用Kc
中的属性定义Mapped Type:
type C = {
[K in keyof A & keyof B]: A[K] | B[K]
}
这定义了一种新类型,其中每个键都会出现在A
和B
中。
与此密钥相关联的每个值都将具有A[K] | B[K]
类型,以防A[K]
和B[K]
不同。
仅当在A和B中键入相同时,使用Conditional Type将键映射到值:
type MappedC = {
[K in keyof A & keyof B]:
A[K] extends B[K] // Basic check for simplicity here.
? K // Value becomes same as key
: never // Or `never` if check did not pass
}
通过访问所有密钥,从此对象获取所有值的联合:
// `never` will not appear in the union
type Kc = MappedC[keyof A & keyof B]
最后:
type C = {
[K in Kc]: A[K]
}
答案 1 :(得分:2)
type Common<A, B> = Pick<
A,
{
[K in keyof A & keyof B]: A[K] extends B[K]
? B[K] extends A[K]
? K
: never
: never;
}[keyof A & keyof B]
>;
答案 2 :(得分:1)
基于@kube's answer,您可以使用泛型来创建可重用的类型:
type Common<A, B> = {
[P in keyof A & keyof B]: A[P] | B[P];
}
这允许您动态创建交叉点:
const c: Common<T1, T2> = { y: 123 };
答案 3 :(得分:1)
虽然其他答案中通常建议使用以下类型:
type Common<A, B> = {
[P in keyof A & keyof B]: A[P] | B[P];
}
无法检查属性值是否可以相互分配。
这意味着 Common<A, B>
可能具有以下属性
A
和 B
并未真正共享。
type A = { a: number; x: string; z: number }
type B = { b: number; x: number; z: number}
Common<A, B> // => { x: string | number; z: number}
// above should just be { z: number }, since the type of property x is not
// assignable to the type of property x in both A and B.
这很糟糕的原因是因为解构 Common<A, B>
类型的对象
进入 A
类型或 B
类型的对象可能因 A
或 B
失败。
例如,
const sharedProps: Common<A, B> = { x: 'asdf', z: 9 }
const a: A = { ...sharedProps, a: 1 }
// below throws type error; string not assignable to number
const b: B = { ...sharedProps, b: 1 }
这令人困惑,并且对我们可以用 泛型。
我建议使用以下类型(适用于 TS4.1+):
/**
* Omits properties that have type `never`. Utilizes key-remapping introduced in
* TS4.1.
*
* @example
* ```ts
* type A = { x: never; y: string; }
* OmitNever<A> // => { y: string; }
* ```
*/
type OmitNever<T extends Record<string, unknown>> = {
[K in keyof T as T[K] extends never ? never : K]: T[K];
};
/**
* Constructs a Record type that only includes shared properties between `A` and
* `B`. If the value of a key is different in `A` and `B`, `SharedProperties<A,
* B>` attempts to choose a type that is assignable to the types of both values.
*
* Note that this is NOT equivalent to `A & B`.
*
* @example
* ```ts
* type A = { x: string; y: string; }
* type B = { y: string; z: string }
* type C = { y: string | number; }
*
* A & B // => { x: string; y: string; z: string; }
* SharedProperties<A, B> // => { y: string; }
* SharedProperties<B, C> // => { y: string | number; }
* ```
*/
type SharedProperties<A, B> = OmitNever<Pick<A & B, keyof A & keyof B>>;
此类型正确返回保证是 A
和 B
的子类型的共享属性,因为 A & B
保证是 A
和 {{ 1}} 只要 B
不是 A & B
。
never