Отображение типа объединения в соответствии с полем - PullRequest
1 голос
/ 11 апреля 2020

У меня есть тип объединения, и у каждого подтипа есть поле типа. Я хочу автоматически создать тип, поля которого являются различными значениями типа, а значения являются соответственно массивами соответствующего подтипа. Не знаю, понятно ли это, но этот пример поможет:

// What I have :

type A = { type: "A" };
type B = { type: "B" };
type C = { type: "C" };
type MyUnion = A | B | C;

// What I want automatically generated :

type Keyed = {
  A: A[];
  B: B[];
  C: C[];
};

Есть ли способ сделать это без , вручную сопоставив "A" с тип A, et c., задано только MyUnion?

Я подумал о чем-то вроде:

type Keyed = {
  [T in MyUnion["type"]]: ??
};

Но тогда я не знаю, как "разбить" MyUnion в отдельных подтипах на основе T.

1 Ответ

1 голос
/ 11 апреля 2020

Я думаю, что это способ сделать это:

type Keyed<T extends MyUnion> = {
    [P in T["kind"]]: T extends (infer U)
        ? T["kind"] extends P
            ? U[] : never
        : never
}

но это довольно запутанно. Возможно, более удобочитаемо просто написать класс Keyed вручную.

Требуются цепные операторы extends, потому что вы хотите быть уверенными, что в массиве нет разных типов. Например, компилятор предупредит вас об этом, потому что у вас есть типы «A» и «B» в массиве «A»:

var c: Keyed<MyUnion> = {
    "A": [{ kind: "A" }, { kind: "B" }], // Error on 2nd item, bacause "B"
    "B": [{ kind: "B" }],
    "C": []
}

Это действительные данные:

var c: Keyed<MyUnion> = {
    "A": [{ kind: "A" }, { kind: "A" }],
    "B": [{ kind: "B" }],
    "C": []
}

Я переименовал собственность type в kind. Он соответствует соглашению в документации TypeScript и позволяет избежать путаницы при использовании ключевого слова type для имени свойства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...