Проблема

Вычислите разницу между объектами O & O1. Например:

type Foo = {
  name: string;
  age: string;
};

type Bar = {
  name: string;
  age: string;
  gender: number;
};

type test0 = Diff<Foo, Bar>; // expected { gender: number }

Решение

Очевидно, что в этой проблеме нужно манипулировать объектами. Поэтому, вероятно, что сопоставляющие типы здесь сыграют свою роль.

Начнём с сопоставляющего типа, в котором перебираем объединение свойств двух объектов. Прежде чем искать разницу двух объектов, нужно же собрать все их свойства в один.

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

Когда мы перебираем ключи первого или второго объекта, проверяем, а существует ли свойство на том или ином объекте. Добавим условный тип, в котором проверим наличие свойств в объектах:

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

Отлично! У нас есть объект, который содержит в себе объединение двух объектов. Последнее что нужно сделать - отфильтровать те свойства, которые существуют в двух объектах одновременно.

Но как мы можем узнать какие свойства существуют в двух объектах? Типы пересечений! Возьмем пересечение свойств двух объектов и исключим типы в пересечении из нашего сопоставляющего типа P:

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

Что почитать