为什么在键入接受函数的高阶函数参数时键入“Function”不起作用?
Why type `Function` doesn't work when typing a higher-order function parameter that accepts a function?
我想输入一个函数作为输入:
- 数组
- 过滤逻辑函数(谓词函数)
在 JavaScript 中,以下按预期工作:
const myFilter = (func, arr) => arr.filter(func)
const myArr = [1, 2, 3, 4, 5, 6]
const res = myFilter(x => x > 3, myArr)
console.log(res) // => [ 4, 5, 6 ]
但是,在 TypeScript 中它会抛出一个错误:
const myFilter = (func: Function, arr: any[]): any[] => arr.filter(func)
// ^
// (parameter) func: Function
// No overload matches this call.
虽然输入func
为any
解决了错误,但我还是想知道:
- 为什么那个类型
Function
不起作用?
func
参数的正确类型是什么?
Function
指的是js函数class用于从字符串创建函数
改为使用以下语法:func: (current: T, i: number, arr: T[]) => boolean
。此类型创建一个 Array.prototype.filter
接受的回调类型,因为它模仿了它的参数和 return 类型。
使用泛型,您可以拥有接受任何类型的 HOF 函数:
function myFilter<T>(func: (current: T, i: number, arr: T[]) => boolean, arr: T[]): T[] {
return arr.filter(func);
}
console.log(myFilter((v) => v % 2 === 0, [1, 2, 3, 4, 5, 6]));
如果您不想使用泛型并将函数限制为特定类型,只需删除 <T>
并将 T
替换为所需的类型。
有了泛型就可以写了,看第二个参数func
定义的好像是回调。 Array<T>
- 这被称为泛型类型,其中 T 是调用函数时提供的泛型类型,无论你提供什么都会变成 T。Sp 它可以是数字或字符串或整数,如果你传递你的数字例如发送 T 将 te 号码。
const myFilter = <T,>(arr: Array<T>, func: (value: T) => any) => {
return arr.filter(func);
}
const myArr = [1, 2, 3, 4, 5, 6];
const res = myFilter(myArr, x => x > 3);
console.log(res);
你甚至可以像这样限制类型。所以现在你必须总是传递数字数组而不是其他任何东西。
const myFilter = <T extends number>(arr: Array<T>, func: (value: T) => any) => {
return arr.filter(func)
}
根据你的具体问题,不使用泛型,可以简单地写成这样,
const myFilter = (arr: Array<any>, func: (value: number) => any) => {
return arr.filter(func)
}
const myArr = [1, 2, 3, 4, 5, 6]
const res = myFilter(myArr, x => x > 3)
console.log(res);
为了最大化你的函数的效用,你可以这样写multiple overloads:
- 接受 generic type guard predicate function
- 一个接受标准布尔值 predicate function for
array.filter
通过为类型保护版本编写一个重载,您可以推断谓词中的保护类型并在原始 array/tuple 是齐次的情况下得到一个缩小的数组(参见示例 2)。
type ArrayItemPredicate<U, T extends U> = (
value: U,
index: number,
array: readonly U[],
) => value is T;
function myFilter <U, T extends U, A extends readonly U[]>(
arr: A,
filterPredicate: ArrayItemPredicate<U, T>,
): T[];
function myFilter <A extends readonly unknown[]>(
arr: A,
filterPredicate: Parameters<A['filter']>[0],
): A[number][];
function myFilter <
U,
T extends U,
A extends readonly U[],
Predicate extends ArrayItemPredicate<U, T> | Parameters<A['filter']>[0],
>(arr: A, filterPredicate: Predicate) {
return arr.filter(filterPredicate);
}
{ // example 1: from your question
const arr = [1, 2, 3, 4, 5, 6];
const predicate = (n: number) => n > 3;
const res = myFilter(arr, predicate); // number[]
console.log(res); // [4, 5, 6]
}
{ // example 2: filter to keep only numbers
const arr = [1, 'a', 2, 'b', 3, 4, 'c', 'd', 'e', 'f', 5, 6];
const predicate = (value: string | number): value is number => typeof value === 'number';
const res = myFilter(arr, predicate); // number[]
console.log(res); // [1, 2, 3, 4, 5, 6]
}
我想输入一个函数作为输入:
- 数组
- 过滤逻辑函数(谓词函数)
在 JavaScript 中,以下按预期工作:
const myFilter = (func, arr) => arr.filter(func)
const myArr = [1, 2, 3, 4, 5, 6]
const res = myFilter(x => x > 3, myArr)
console.log(res) // => [ 4, 5, 6 ]
但是,在 TypeScript 中它会抛出一个错误:
const myFilter = (func: Function, arr: any[]): any[] => arr.filter(func)
// ^
// (parameter) func: Function
// No overload matches this call.
虽然输入func
为any
解决了错误,但我还是想知道:
- 为什么那个类型
Function
不起作用? func
参数的正确类型是什么?
Function
指的是js函数class用于从字符串创建函数
改为使用以下语法:func: (current: T, i: number, arr: T[]) => boolean
。此类型创建一个 Array.prototype.filter
接受的回调类型,因为它模仿了它的参数和 return 类型。
使用泛型,您可以拥有接受任何类型的 HOF 函数:
function myFilter<T>(func: (current: T, i: number, arr: T[]) => boolean, arr: T[]): T[] {
return arr.filter(func);
}
console.log(myFilter((v) => v % 2 === 0, [1, 2, 3, 4, 5, 6]));
如果您不想使用泛型并将函数限制为特定类型,只需删除 <T>
并将 T
替换为所需的类型。
有了泛型就可以写了,看第二个参数func
定义的好像是回调。 Array<T>
- 这被称为泛型类型,其中 T 是调用函数时提供的泛型类型,无论你提供什么都会变成 T。Sp 它可以是数字或字符串或整数,如果你传递你的数字例如发送 T 将 te 号码。
const myFilter = <T,>(arr: Array<T>, func: (value: T) => any) => {
return arr.filter(func);
}
const myArr = [1, 2, 3, 4, 5, 6];
const res = myFilter(myArr, x => x > 3);
console.log(res);
你甚至可以像这样限制类型。所以现在你必须总是传递数字数组而不是其他任何东西。
const myFilter = <T extends number>(arr: Array<T>, func: (value: T) => any) => {
return arr.filter(func)
}
根据你的具体问题,不使用泛型,可以简单地写成这样,
const myFilter = (arr: Array<any>, func: (value: number) => any) => {
return arr.filter(func)
}
const myArr = [1, 2, 3, 4, 5, 6]
const res = myFilter(myArr, x => x > 3)
console.log(res);
为了最大化你的函数的效用,你可以这样写multiple overloads:
- 接受 generic type guard predicate function
- 一个接受标准布尔值 predicate function for
array.filter
通过为类型保护版本编写一个重载,您可以推断谓词中的保护类型并在原始 array/tuple 是齐次的情况下得到一个缩小的数组(参见示例 2)。
type ArrayItemPredicate<U, T extends U> = (
value: U,
index: number,
array: readonly U[],
) => value is T;
function myFilter <U, T extends U, A extends readonly U[]>(
arr: A,
filterPredicate: ArrayItemPredicate<U, T>,
): T[];
function myFilter <A extends readonly unknown[]>(
arr: A,
filterPredicate: Parameters<A['filter']>[0],
): A[number][];
function myFilter <
U,
T extends U,
A extends readonly U[],
Predicate extends ArrayItemPredicate<U, T> | Parameters<A['filter']>[0],
>(arr: A, filterPredicate: Predicate) {
return arr.filter(filterPredicate);
}
{ // example 1: from your question
const arr = [1, 2, 3, 4, 5, 6];
const predicate = (n: number) => n > 3;
const res = myFilter(arr, predicate); // number[]
console.log(res); // [4, 5, 6]
}
{ // example 2: filter to keep only numbers
const arr = [1, 'a', 2, 'b', 3, 4, 'c', 'd', 'e', 'f', 5, 6];
const predicate = (value: string | number): value is number => typeof value === 'number';
const res = myFilter(arr, predicate); // number[]
console.log(res); // [1, 2, 3, 4, 5, 6]
}