Принимая дополнения дискриминационных союзов - PullRequest
0 голосов
/ 03 декабря 2018

Допустим, у меня есть следующие различающиеся союзы и некоторые связанные типы

type Union = 'a' | 'b';
type Product<A extends Union, B> = { f1: A, f2: B};
type ProductUnion = Product<'a', 0> | Product<'b', 1>;

Теперь я могу принимать дополнения, используя типы сопоставления и Exclude

type UnionComplement = {
  [K in Union]: Exclude<Union, K>
};
// {a: "b"; b: "a"}

type UnionComplementComplement = {
  [K in Union]: Exclude<Union, Exclude<Union, K>>
};
// {a: "a"; b: "b"}

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

type ProductComplement = {
  [K in Union]: Exclude<ProductUnion, { f1: K }>
};
// {a: Product<'b', 1>; b: Product<'a', 0>}

Двойное дополнение некорректно, независимо от того, что я пытаюсь

type ProductComplementComplement = {
  [K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
};
// {a: ProductUnion; b: ProductUnion}

Я не понимаю, где ошибка, потому что, если я заменяю типы, то онадолжно сработать.Существует только 2 значения для K при приеме двойного дополнения, поэтому давайте попробуем первое

type First = Exclude<ProductUnion, Exclude<ProductUnion, { f1: 'a' }>>;
// {f1: 'a'; f2: 0}

Второе также работает

type Second = Exclude<ProductUnion, Exclude<ProductUnion, { f1: 'b' }>>;
// {f1: 'b'; f2: 1}

Все составные части работают, но когда объединеныв типе отображения это, кажется, ломается.Что мне здесь не хватает?

По какой-то причине я попытался добавить параметр типа, чтобы посмотреть, что произойдет, путем абстрагирования дополняющего процесса

type Complementor<T> = {
    [K in Union]: Exclude<T, { f1: K }>
};

type DoubleComplementor<T> = {
    [K in Union]: Exclude<T, Exclude<T, { f1: K }>>
};

Теперь, если я применю параметризованные типы к ProductUnion работает точно так, как я ожидаю

type Complement = Complementor<ProductUnion>;
// {a: Product<'b', 1>; b: Product<'a', 0>}

type DoubleComplement = DoubleComplementor<ProductUnion>;
// {a: Product<'a', 0>; b: Product<'b', 0>}

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Это действительно было ошибкой: https://github.com/Microsoft/TypeScript/issues/28824. Благодаря Андерсу и команде следующий выпуск должен иметь более последовательное поведение.

0 голосов
/ 03 декабря 2018

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

РЕДАКТИРОВАТЬ :

Хорошо, это похоже на ошибку.

type E1 = Exclude<{ f1: 'a' } | { f1: 'b' },
            Exclude<{ f1: 'a' } | { f1: 'b' }, { f1: 'a' }>>;

// E1 = { f1: "a" }

type E2<K> = Exclude<{ f1: 'a' } | { f1: 'b' },
               Exclude<{ f1: 'a' } | { f1: 'b' }, { f1: K }>>;

// E2<K> = { f1: "a" } | { f1: "b" }
//         ^ no `K` in the resulting type
//         the compiler has somehow eliminated `K` from the resulting type

// no matter what you do from here on, doesn't get re-evaluated with K in it.
//
type E2a = E2<'a'>;
// E2a = { f1: "a" } | { f1: "b" }

type E2b = E2<'b'>;
// E2b = { f1: "a" } | { f1: "b" }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...