【问题标题】:TS2346: Supplied parameters do not match any signature of call target -- array reduce function signatureTS2346:提供的参数与调用目标的任何签名都不匹配——数组减少函数签名
【发布时间】:2017-11-23 08:46:47
【问题描述】:

这是我的函数签名:

export type ReduceCallback<TVal,TAcc> 
    = (accumulator: TAcc, currentValue: TVal, currentIndex: number, array: TVal[]) => TAcc


export function reduceArray<TVal,TAcc>(
    iterable: Iterable<TVal>,
    callback: ReduceCallback<TVal,TAcc>,
    initialValue: TAcc
): TAcc;
export function reduceArray<TVal>(
    iterable: Iterable<TVal>,
    callback: ReduceCallback<TVal,TVal>,
    initialValue?: TVal
): TVal {
    let arr = toArrayStrict(iterable);
    if(initialValue === undefined) {
        return arr.reduce(callback); // 2nd arg has to be fully omitted
    }
    return arr.reduce(callback, initialValue);
}

我是这样称呼它的:

reduceArray([0,1,2,3], (acc, val) => acc + val)

tsc 在抱怨:

TS2346:提供的参数与调用目标的任何签名都不匹配。

但我不知道为什么。我的调用应该匹配第二个函数签名,不是吗?我在通话中省略了initialValue,所以它应该别无选择,只能匹配第二个签名。

[0,1,2,3]Iterable&lt;number&gt;ReduceCallback 应该使用 ReduceCallback&lt;number,number&gt;,这意味着 accval 是数字。

有什么问题?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你有两个问题。首先,当您调用 reduceArray 时,它会尝试使用第一个重载,因为 initialValue 是非可选的类型。其次,您要查找的 Array.reduce() 的重载具有非可选的第二个参数。

    reduce<U>(callbackfn: (previousValue: U, currentValue: T, 
              currentIndex: number, array: ReadonlyArray<T>) => U, initialValue: U): U;
    

    该方法应该自动计算出“第一次通过”值,因此我简化了该部分。我还用Array.from() 替换了toArrayStrict(),因为我不知道那个方法是什么,但它似乎返回了一个数组类型。

    export type ReduceCallback<TVal, TAcc> = (accumulator: TAcc, currentValue: TVal, currentIndex: number, array: Array<TVal>) => TAcc
    
    export function reduceArray<TVal, TAcc>(
               iterable: Iterable<TVal>,
               callback: ReduceCallback<TVal, TAcc>,
               initialValue?: TAcc
           ): TAcc;
    export function reduceArray<TVal>(
               iterable: Iterable<TVal>,
               callback: ReduceCallback<TVal, TVal>,
               initialValue?: TVal
           ): TVal
    {
        let arr = Array.from(iterable);
        return arr.reduce(callback, initialValue);
    }
    
    let result = reduceArray([0, 1, 2, 3], (acc: number, val) => acc + val);
    console.log(result);
    

    【讨论】:

    • 我不明白。为什么它会使用第一个重载?在我的第一次重载中,initiaValue 是非可选的,并且我没有在我的调用中提供 initialValue——因此,它不能使用该重载吗?我正在查看lib.d.ts 中的定义以及U 的重载,initialValue 在那里也是非可选的。
    • 关于那个我没有给你一个好的答案,但我确实发现如果你翻转你的重载,它会与具有非可选 initialValue 的重载一起编译。试图找到专门关于使用可选参数重载的文档。您可以发布您所指的超载吗?我没有看到带有可选 initialValue 参数的 reduce&lt;U&gt;
    • Ctrl+点击 PhpStorm 中的reduce 出现:reduce&lt;U&gt;(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) =&gt; U, initialValue: U): U。那一个是非可选的。另一个是:reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) =&gt; T, initialValue?: T): T
    • PS:y2bd 给出了很好的解释。函数体正上方的函数签名不算作声明,因此 TypeScript 不使用它。这就是为什么交换顺序会改变事情。
    • 在您的情况下,后一种重载不适用,因为您的 currentValue (TVal) 的类型不同于其他变量 (TAcc) (T = TVal, U = TAcc)。
    【解决方案2】:

    你的重载语法有点错误。对于重载,您需要为每个特定重载 声明。实际的函数头不算作声明。这意味着在您的情况下,不幸的是您必须指定函数头两次:

    // because I don't know what toArrayStrict is
    declare function toArrayStrict<T>(it: Iterable<T>): T[];
    
    export type ReduceCallback<TVal, TAcc> 
        = (accumulator: TAcc, currentValue: TVal, currentIndex: number, array: TVal[]) => TAcc
    
    export function reduceArray<TVal,TAcc>(
        iterable: Iterable<TVal>,
        callback: ReduceCallback<TVal,TAcc>,
        initialValue: TAcc
    ): TAcc;
    // here we declare the second overload, which is just a duplicate of the actual function header
    export function reduceArray<TVal>(
        iterable: Iterable<TVal>,
        callback: ReduceCallback<TVal, TVal>,
        initialValue?: TVal
    ): TVal;
    export function reduceArray<TVal>(
        iterable: Iterable<TVal>,
        callback: ReduceCallback<TVal,TVal>,
        initialValue?: TVal
    ): TVal {
        let arr = toArrayStrict(iterable);
        if(initialValue === undefined) {
            return arr.reduce(callback); // 2nd arg has to be fully omitted
        }
        return arr.reduce(callback, initialValue);
    }
    

    来源:https://www.typescriptlang.org/docs/handbook/functions.html(底部)

    【讨论】:

    • 哦!所以它匹配“第一次重载”,因为我的版本中真的只有一个重载/签名?知道了。这样就搞定了,谢谢!
    • 是的!看起来你明白了。一般的推理是,有时实际的函数头需要具有联合和交集以及可选类型的奇怪组合以支持重载,因此值得将其与声明分开。但是,您的情况确实有点奇怪,只是复制您的标题以使其工作。
    猜你喜欢
    • 2016-02-15
    • 2016-06-09
    • 2017-04-28
    • 2017-08-24
    • 2017-02-25
    • 2017-07-26
    • 2018-03-31
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多