将一种类型的数组转换为该类型的映射对象

时间:2020-01-03 03:23:50

标签: typescript

我想做这样的事情:

type Foo = {
    name: string;
    value: any;
}

const myFoos: Foo[] = [
    {
        name: "hello",
        value: 1,
    },
    {
        name: "world",
        value: "bar"
    }
];


function createObjectFromFooArray(foos: Foo[]) : Record<string, Foo> {  //Need to change the return type
    return foos.reduce((acc, cur) => {
        return {
            ...acc,
            [cur.name]: cur
        }
    }, {});
}


const objectFoos = createObjectFromFooArray(myFoos); 

console.log(objectFoos.hello); 
console.log(objectFoos.aaa); //Should error

也就是说-给定一个Foo s数组,我想创建一个Foo s的映射对象,并且我希望该对象只包含属于name属性的索引原始Foo数组的元素。我该怎么做?

1 个答案:

答案 0 :(得分:1)

这里有一些问题。一种是您必须拒绝将myFoos注释为Foo[],因为这会使编译器将name属性扩展到string,而您需要跟踪{{3 }},例如"hello""world"。相反,您应该使用string literal types之类的字词,以使myFoos的类型尽量缩小:

const myFoos = [
  {
    name: "hello",
    value: 1,
  },
  {
    name: "world",
    value: "bar"
  }
] as const;

然后,您可以使createObjectFromFooArray的元素类型为T的类型foos中的T是通用的,其中Foo限于name,但可以更具体。并且返回类型可以是条件映射类型,该条件映射类型迭代键的T的{​​{1}}属性,并为每个属性值提取相应的value属性:

function createObjectFromFooArray<T extends Foo>(foos: readonly T[]) {  
  return foos.reduce((acc, cur) => {
    return {
      ...acc,
      [cur.name]: cur
    }
  }, {} as { [K in T["name"]]: Extract<T, { name: K }>});
}

行为符合您的预期:

const objectFoos = createObjectFromFooArray(myFoos);    
console.log(objectFoos.hello);
console.log(objectFoos.aaa); // error!

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

const assertion