#typescript
Вопрос:
Я пытаюсь написать довольно сложную инструкцию reduce, в которой я превращаю массив, а также массив массивов в массив объектов. Вот мои начальные массивы и тип, который я хотел бы получить:
const fruits = ['apple', 'banana', 'pear', 'plum', 'grape'];
const fruitConsumers = [
['Jeremy, Claude', '', '', 'Helen, Benny, Sophie', ''],
['', 'Francis, Paul', '', 'Alice', 'Bob, Tracy', 'Lacey, Stacey'],
];
type FruitPersonMap = {
apple: string[],
banana: string[],
pear: string[],
plum: string[],
grape: string[],
people?: {
name: string,
fruit: string,
}[]
}
По большей части это работает довольно хорошо, за исключением той части, где я хотел бы иметь в конце список всех людей и их плодов. По какой-то причине typescript это не нравится. Вот моя функция:
const makeFruitPersonMap = (fruits: string[], consumers: string[][]): FruitPersonMap[] => {
return consumers.map(consumerSet => {
return consumerSet.reduce((acc, val: string, i: number) => {
// the nth item in a consumer list will always correspond to the nth fruit
const currentFruit = fruits[i];
// turn the people into an array instead of a comma separated string
const peopleList = val.split(',').map(name => name.trim());
// turn the array of people into an array of objects with keys name, fruit
const peopleWithFruit = peopleList.map(person => ({
name: person,
fruit: currentFruit,
}))
// add the current key to the accumulator and add the people objects onto the list.
return {
...acc,
[currentFruit]: peopleList,
people: peopleWithFruit ? acc.people.concat(peopleWithFruit) : acc.people
}
}, { people: [] }) as FruitPersonMap
})
};
Это приводит меня к ошибке: Conversion of type '{ people: never[]; }' to type 'FruitPersonMap' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first
Чего я не понимаю, так это почему people
ключу задан тип never[]
. Объединение вещей в people
массив также создает для меня эту проблему, что для меня странно. Я также попытался добавить people
ключ в функцию обратного вызова ( if (!acc.people) acc.people = []
), но затем я получаю сообщение об ошибке о acc.people
том, что он не существует {}
. Я имею в виду, я согласен, что это плохой способ установить значение people
ключа, но я проверил, существует ли он или нет. В чем дело!
Так что, я думаю, мой вопрос двоякий. Почему Typescript недоволен этим конкретным способом обработки reduce и есть ли способ настроить начальное значение reduce, которое не приводит к этой проблеме?
Ответ №1:
Я понял это примерно через 30 секунд после того, как набрал весь вопрос.
Новый тип:
type PeopleList = {
people: {
name: string,
fruit: string,
}[]
}
Обновленная функция:
const testFunc = (fruits: string[], consumers: string[][]) => {
return consumers.map(consumerSet => {
return consumerSet.reduce((acc, val: string, i: number) => {
const currentFruit = fruits[i];
const peopleList = val.split(',').map(name => name.trim());
const peopleWithFruit = peopleList.map(person => ({
name: person,
fruit: currentFruit,
}))
return {
...acc,
[currentFruit]: peopleList,
people: peopleWithFruit ? acc.people.concat(peopleWithFruit) : acc.people
}
}, { people: [] } as PeopleList) as FruitPersonMap
})
};
{ people: [] } as PeopleList
Примечание. установка типа на начальное значение, которое перекрывается с FruitPersonMap, исправляет это.
Подумал, что оставлю этот вопрос открытым на случай, если кто-нибудь еще столкнется с этой проблемой и запутается, как это сделал я.