Преобразование массива в объект с ключом из общего свойства в элементах массива - PullRequest
0 голосов
/ 21 июня 2020

У меня есть объект, похожий на этот:

const v = [
  { pointer: "/name", name: "N1" },
  { pointer: "/name", name: "N2" },
  { pointer: "/zip", name: "Z1" }
] as const

, и я хотел бы создать такие объекты:

const m: M = {
  "/name": [{ pointer: "/name", name: "N2" }] // can also contain N1, but not Z1
}

Можно ли создать для этого тип? Моя попытка должна лучше объяснить, что я пытаюсь сделать:

type V = typeof v;
type T = V[number]

type M = {
  [K in T["pointer"]]: Array<T extends {pointer: K} ? T : never>;
}

codeandbox: https://codesandbox.io/s/56564

1 Ответ

1 голос
/ 21 июня 2020

Вы близки, но проблема в том, что ваш T является конкретным типом, а не параметром обобщенного типа c, и, следовательно, T extends { pointer: K } ? T : never не распространяется по объединениям . Таким образом, T extends { pointer: K } будет просто ложным для каждого варианта K, и вы получите never[] вместо того, что ищете.

Самый простой способ вернуть распределительные условные типы - использовать введите псевдоним в форме type Something<X> = X extends { pointer: K } ? X : never, а затем вставьте Something<T>. К счастью, встроенная утилита Extract<T, U> типа уже работает таким образом. Итак, мы можем написать это:

type M = { [K in T["pointer"]]?: Array<Extract<T, { pointer: K }>> };

, что дает:

/* 
type M = {
    "/name"?: ({
        readonly pointer: "/name";
        readonly name: "N1";
    } | {
        readonly pointer: "/name";
        readonly name: "N2";
    })[];
    "/zip"?: {
        readonly pointer: "/zip";
        readonly name: "Z1";
    }[];
}
*/

Что, я думаю, ближе к тому, что вы хотите. Обратите внимание, что я сделал реквизиты необязательными, поскольку ваша константа m не имеет всех реквизитов:

const m: M = {
    "/name": [{ pointer: "/name", name: "N2" }]
}; // okay

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

...