首页 > 解决方案 > TypeScript如何在数组上的Reduce函数上设置累积值和初始值的类型

问题描述

我在 typescriptlang.org(打字稿游乐场)上运行当前代码

我已经阅读了 typeScript 中类型的重要性以及如何在函数中使用它们。但是,我正在努力在此 reduce 方法中添加以下类型:

// Types for car
type Car = {
 name:string,
 age:number,
 registered: boolean
};

// Reduce function to hopefully get the total number of cars that are registered.

function totalRegisteredCars(cars:Car[]) {
 cars.reduce((acc:number , car:Car) => {
    if(car.registered === true ) {
        acc + 1;
    }
 },0);
}

var cars = [
{name:'vw' , age: 30, registered: true},
{name:'vw' , age: 32, registered: true},
{name:'Merc' , age: 25, registered: false},
{name:'bmw' , age: 20, registered: false},
{name:'bmw' , age: 21, registered: true},
{name: 'ford', age: 31, registered: false},
{name: 'pinto', age: 43, registered: false},
{name: 'uno', age: 41, registered: true},
{name: 'ford', age: 30, registered: true},
{name: 'Mustang', age: 19, registered: false}
];

console.log(totalRegisteredCars(cars));

https://www.typescriptlang.org/play中有此内容时,我收到以下错误:


错误信息

没有重载匹配此调用。重载 1 of 3, '(callbackfn: (previousValue: Car, currentValue: Car, currentIndex: number, array: Car[]) => Car, initialValue: Car): Car',给出以下错误。

'(acc: number, car: Car) => void' 类型的参数不可分配给 '(previousValue: Car, currentValue: Car, currentIndex: number, array: Car[]) => Car' 类型的参数。参数“acc”和“previousValue”的类型不兼容。“汽车”类型不能分配给“数字”类型。

重载 2 of 3, '(callbackfn: (previousValue: number, currentValue: Car, currentIndex: number, array: Car[]) => number, initialValue: number): number',给出以下错误。'(acc: number, car: Car) => void' 类型的参数不可分配给 '(previousValue: number, currentValue: Car, currentIndex: number, array: Car[]) => number' 类型的参数。类型 'void' 不能分配给类型 'number'。


问题

我可能错过了一个简单的步骤,但编译器抱怨我输入为数字的累加器和输入为 Car 的汽车似乎给了我上面记录的错误。

我只想知道为什么我不能将累加器的类型设置为数字。将来我应该如何在reduce函数中设置类型?

标签: javascripttypescripttypesmodelreduce

解决方案


您收到错误的原因是您的 reduce 回调未正确实现。它应该在遍历数组的每个元素后返回 reduce 操作的结果。

function totalRegisteredCars(cars: Car[]) {
 cars.reduce((acc:number , car:Car) => {
    let newReducedValue = acc;
    if(car.registered === true ) {
        newReducedValue = acc + 1;
    }
    return newReducedValue;
 }, 0);
}

当然,没有必要写这么多行,但我想把问题出在哪里。这是编写相同内容的另一种方法:

cars.reduce((acc: number, car: Car) => acc + car.registered ? 1 : 0, 0);
// or even use car.registered by itself, JS will cast it to a number,
// I just prefer to make it more obvious

我注意到您的代码的另一件事是类型签名totalRegisteredCars实际上是(cars: Car[]) => void,因为函数本身没有 return 语句。我们将 Cars 数组减少为一个数字,但随后我们对该数字什么也不做。

您可能打算从您的totalRegisteredCars函数中返回一个数字(然后记录它)。提醒自己和编译器的一个好方法是添加一个显式返回类型,如下所示:

function totalRegisteredCars(cars: Car[]): number {

一旦你这样做,你会注意到你得到一个新的错误:

A function whose declared type is neither 'void' nor 'any' must return a value. (2355)

此时我们可以说“谢谢,Typescript”并修复代码以实现我们的意图,同时思考类型有多大帮助。

function totalRegisteredCars(cars: Car[]): number {
  return cars.reduce((acc, car) => acc + car.registered ? 1 : 0, 0);
}

请注意,在我的最新示例中,我根本没有在 lambda 函数中使用类型声明。原因是类型 ofcar是从 type of 推断出来的cars,而类型 ofacc是从函数的第二个参数推断出来的reduce0

最后一点,我想补充一点,以上所有内容都是假设您只是在使用该语言。如果您真的打算计算在您的汽车阵列中注册的汽车数量,一种可能更简单的方法是

cars.filter(car => car.registered).length

推荐阅读