Diff

挑战

获取两个接口类型中的差值属性。

type Foo = {
  a: string;
  b: number;
};
type Bar = {
  a: string;
  c: boolean;
};
 
type Result1 = Diff<Foo, Bar>; // { b: number, c: boolean }
type Result2 = Diff<Bar, Foo>; // { b: number, c: boolean }

解答

要找到差值属性,我们首先要得到两个对象的所有属性。

type Diff<O, O1> = {
  [P in keyof (O & O1)]: never;
};

接下来我们筛选差值属性。

对于任意一个属性,有三种可能:

  1. 只存在于 O
  2. 只存在于 O1
  3. 既存在于 O 中,也存在于 O1

我们可以先判断该属性是不是在 O 中。如果不在,肯定只属于 O1,是我们想要的属性;如果在 O 中,再判断是不是在 O1 中,如果不在,说明只存在于 O 中,也是我们想要的属性,否则舍弃掉。

type Diff<O, O1> = {
  [P in keyof (O & O1) as P extends keyof O
    ? P extends keyof O1
      ? never
      : P
    : P]: never;
};

现在我们得到了所有差值属性,接下来给属性加上对应的类型。

type Diff<O, O1> = {
  [P in keyof (O & O1) as P extends keyof O
    ? P extends keyof O1
      ? never
      : P
    : P]: P extends keyof O ? O[P] : P extends keyof O1 ? O1[P] : never;
};

这道题在 Issue 区还有一个更精妙的答案,这里直接贴出来。

// O&O1 - O|O1
// & means 'either has', | means 'both have'
type Diff<O, O1> = {
  [K in keyof (O & O1) as K extends keyof (O | O1) ? never : K]: (O & O1)[K];
};

核心就是 keyof (O | O1) 会得到两者都有的属性,具体的解释大家可以去 GitHub 查看。

参考链接