Bill
Bill

Reputation: 5150

How should the accumulator and current arguments for reduce() be typed?

How should the accumulator and current arguments to reduce be typed?

interface CountriesContinent {
  continent: string;
  countries: string[];
}

interface ZebraInCountry {
  countryName: string;
  population: number;
}

interface ContinentCount {
  continent: string;
  population: number;
}

export const getAnimals = async (
  zebraInCountry: ZebraInCountry[],
  countriesByArea: CountriesContinent[]
): Promise<ContinentCount[] | null> => {
  return countriesByArea.map((obj: CountriesContinent) => {
    const { continent, countries } = obj;
    return zebraInCountry
      .filter(obj => countries.includes(obj.countryName))
      .reduce((acc, cur) => {
        const population = acc.population + cur.population;
        return { population, continent };
      });
  });
};

const zebraInCountry = [
  { countryName: "Nigeria", population: 100 },
  { countryName: "Ghana", population: 200 },
  { countryName: "Sudan", population: 300 },
  { countryName: "North America", population: 400 },
  { countryName: "South America", population: 100 }
];
const countriesByArea = [
  { continent: "Africa", countries: ["Nigeria", "Ghana", "Sudan"] },
  { continent: "America", countries: ["North America", "South America"] }
];

const zebraPerArea = getAnimals(zebraInCountry, countriesByArea);

console.log(zebraPerArea);

The error I'm getting is on the reduce arguments of acc and cur

Argument of type '(acc: ZebraInCountry, cur: ZebraInCountry) => { population: number; continent: string; }' is not assignable to parameter of type '(previousValue: ZebraInCountry, currentValue: ZebraInCountry, currentIndex: number, array: ZebraInCountry[]) => ZebraInCountry'.
  Property 'countryName' is missing in type '{ population: number; continent: string; }' but required in type 'ZebraInCountry'.

Upvotes: 0

Views: 34

Answers (1)

Yuval
Yuval

Reputation: 1232

Reduce accepts a Generic parameter that specifies its accumulator type. Also is it accepts the initial value as the second parameter.

  const { continent, countries } = obj;
  
  return zebraInCountry
    .filter(obj => countries.includes(obj.countryName))
    .reduce<ContinentCount>((acc, cur) => {
      const population = acc.population + cur.population;
      return { population, continent };
    }, {population: 0, continent});

TS playground

Upvotes: 1

Related Questions