首页 > 解决方案 > 将数组转换为具有来自数组元素中的公共属性的键的对象

问题描述

我有一个类似的对象:

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>;
}

密码沙盒: https ://codesandbox.io/s/56564

标签: typescriptconditional-types

解决方案


你很接近,但问题是你T是一个具体类型而不是泛型类型参数,因此T extends { pointer: K } ? T : never不会分配 unions。所以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

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读