Вам просто нужно предоставить начальное значение для функции 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