【问题标题】:Array reduce and optional values in typescript打字稿中的数组减少和可选值
【发布时间】:2018-10-06 11:02:48
【问题描述】:

假设我有以下可折叠界面:

export interface Foldable<F> {
  reduce: <A>(fn: (b: A, a: A) => A, initial: A, foldable: F) => A;
}

然后我想为数组实现它:

export const getArrayFold = <A>(): Foldable<Array<A>> => {
  return {
    reduce: (fn, initial, array) => {
      return array.reduce(fn, initial);
    }
  };
};

但编译器抱怨:

类型“(b:A,a:A)=> A”的参数不能分配给参数 类型'(previousValue:A,currentValue:A,currentIndex:数字,数组: A[]) => A'。参数“a”和“currentValue”的类型是 不相容。 类型“A”不可分配给类型“A”。存在同名的两种不同类型,但它们不相关。

我不明白这里有两种不同类型的A

【问题讨论】:

    标签: typescript


    【解决方案1】:

    有两个错误:

    • 您需要提供数组的类型。无法从单个泛型Array&lt;T&gt; 中获取,需要同时引入TArray&lt;T&gt;
    • reduce 使用的函数类型不合适。正确一:(previousValue: A, currentValue: F) =&gt; A

    解释:

    如果您提供 initial 值和类型(例如string)来减少功能,previousValue 参数始终与 initial 相同。

    见官方TypeScript reduce declaration

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

    完整代码(重构)

    interface Foldable<F, T> {
        reduce: <A>(
            fn: (previousValue: A, currentValue: T) => A,
            initial: A,
            foldable: F
        ) => A;
    }
    
    const getArrayFold = <T>(): Foldable<T[], T> => ({
        reduce(fn, initial, array) {
            return array.reduce(fn, initial);
        }
    });
    
    // Real implementation usage
    const array: number[] = [1, 2, 3]
    const initial: string = "";
    const fn: (previousValue: string, currentValue: number) => string = (a, b) => a + b;
    
    const newValue: string = getArrayFold().reduce(fn, initial, array);
    

    查看TypeScript playground上的代码

    【讨论】:

    • 谢谢。我的用例有所不同,但您的回答提醒我需要输入累加器,这让一切顺利!
    【解决方案2】:

    如果更改泛型类型名称,会更容易看到发生了什么:

    export const getArrayFold = <R>(): Foldable<Array<R>> => {
    

    现在您将收到Type 'R' is not assignable to type 'A'array.reduce 对当前值和先前值使用不同的类型,因此您有类型 A(来自您的接口的泛型类型)和来自您的 getArrayFold 函数的类型 R

    您实际上并没有将泛型类型A 传递给reduce,因此它认为它是来自接口的A,这基本上意味着它无法确定应该是什么类型。

    我发现的一种方法是允许您的界面指定AF 的类型:

    export interface Foldable<F, A> {
      reduce: (fn: (b: A, a: A) => A, initial: A, foldable: F) => A;
    

    现在您可以将数组函数编写为

    getArrayFold = <R>(): Foldable<Array<R>, R>
    

    当你调用它时,你可以做

    getArrayFold<string>().reduce((a, b) => a + b, '', ['hello', 'world']);
    

    这将为您提供类型安全,因此您不能在 a/b 属性或类似的东西上使用 0 作为值或 .toFixed

    【讨论】:

      猜你喜欢
      • 2017-09-22
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 2021-04-05
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多