减少一组谓词功能

时间:2018-10-10 23:23:50

标签: javascript typescript reducers

在我们称为searchForAcceptableNumber的函数中有一系列谓词。

searchForAcceptableNumber(arrayOfNumbers: number[], ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>): number[] {
    const acceptableNumbers: number[] = [];

    const isNumberAcceptablePredicate: (aNumber: number) => boolean = (aNumber: number) => {
        const isLabelAcceptableReducer = (accumulator, currentValue) => accumulator && currentValue(aNumber);
        return isNumberAcceptablePredicates.reduce(isLabelAcceptableReducer);
    };

    arrayOfNumbers.forEach((aNumber: number) => {
        if (isNumberAcceptablePredicate(aNumber)) {
            acceptableNumbers.push(aNumber);
        }
    });
    return acceptableNumbers;
}

您明白了。从本质上讲,它会反复进行,所有工作都很好……除了isNumberAcceptablePredicate不断出现类型为(aNumber: number) => (aNumber: number) => boolean的错误外,其他一切都很好。我可以摆脱这种类型,它将全部编译并正常工作。奇怪的是,如果我在调试会话期间将鼠标悬停在isNumberAcceptablePredicate上,它表示确实是(aNumber: number) => boolean类型。

这不一定是代码中断,也就是说,我最终将此谓词传递给需要类型(aNumber: number) => boolean的其他函数,因此它确实引入了代码中断并增加了约束。我确定我缺少一些荒谬的东西,我只是无法分辨。

1 个答案:

答案 0 :(得分:1)

您只需要向reduce函数提供一个初始值,否则默认使用数组中的第一个元素作为初始值,其类型为(aNumber: number) => boolean而不是boolean

function searchForAcceptableNumber(
  arrayOfNumbers: number[],
  ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>
): number[] {
  const acceptableNumbers: number[] = []

  const isNumberAcceptablePredicate: (aNumber: number) => boolean = (
    aNumber: number,
  ) => {
    const isLabelAcceptableReducer = (accumulator, currentValue) =>
      accumulator && currentValue(aNumber)
    return isNumberAcceptablePredicates.reduce(isLabelAcceptableReducer, true) // <-- initialise to true
  }

  arrayOfNumbers.forEach((aNumber: number) => {
    if (isNumberAcceptablePredicate(aNumber)) {
      acceptableNumbers.push(aNumber)
    }
  })
  return acceptableNumbers
}

您还可以使用诸如此类的内置数组函数大大缩短此函数

function searchForAcceptableNumber(
  arrayOfNumbers: number[],
  ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>
): number[] {
  return arrayOfNumbers.filter(number =>
    isNumberAcceptablePredicates.every(predicate => predicate(number)),
  )
}

如果要概括实现,可以执行以下操作

function filterList<T>(
  values: T[],
  predicates: Array<(val: T) => boolean>,
): T[] {
  return values.filter(val => predicates.every(pred => pred(val)))
}

您还可以使用箭头函数,因为该函数仅返回一个值,有些人出于简洁的目的而喜欢它

const filterList = <T extends any>(
  values: T[],
  predicates: Array<(val: T) => boolean>,
): T[] => values.filter(val => predicates.every(pred => pred(val)))

注意:尽管<T extends any>在语义上是多余的,但extends any的原因还是有必要的,因为<T>本身在语法上是模棱两可的,可以视为JSX标记