使用打字稿泛型来推断参数函数的类型
use typescript generics to infer type of param function
function validate<K>(validationFunc: (...args: (K extends Array<infer T> ? T : K)[]) => boolean, validationArgs: K[]): boolean {
let res: boolean;
for (const validationArg of validationArgs) {
if (Array.isArray(validationArg)) {
res = validationFunc(...validationArg);
} else {
// res = validationFunc(validationArg);
res = (validationFunc as (args: K) => boolean)(validationArg);
}
if(!res)
return false;
}
return true
}
注释行在参数处抛出错误:the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[] ? T : K'.ts(2345)
,而转换版本有效,并且不会抛出任何错误。
如 this playground.
中所示
为什么 typescript 无法推断,在这一行中,K
不能属于 Array<any>
类型,因此允许传递给验证函数?
语义上:
如果第二个参数是 K[]
类型,函数需要接受 K
作为单个参数。
如果第二个参数是 K[][]
类型,函数需要接受 K
.
的多个参数
例如
validate((x: number) => x%2, [1, 2, 3])
应该可以
validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']])
应该可以
validate((x: number) => x%2, ['a', 'b'])
应该抛出错误
validate((x: number) => x%2, [['a', 'a'], ['b', 'b']])
应该抛出错误
编辑:
validate((x: number) => x % 2 === 0, [[1, 2, 3]])
也应该抛出错误,因为验证会破坏 number[][]
一次,并尝试用 number[]
调用 (x: number) => boolean
我认为您不需要推断参数函数的类型。正如您所解释的那样,您的验证参数可以只是 K[] | K[][]
。
我在调用验证函数时也做了一个小改动 x % 2
应该包装在 Boolean()
中,否则 return 值将不正确。
function validate<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
let res: boolean;
for (const validationArg of validationArgs) {
res = validationFunc(validationArg);
if(!res)
return false;
}
return true
}
function simplified<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
return validationArgs.every((args) => validationFunc(args));
}
validate((x: number) => Boolean(x % 2), [[1], [2], [3]]) // should be ok
validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']]) // should be ok
validate((x: number) => Boolean(x % 2), [['a'], ['b']]) // should throw an error
validate((x: number) => Boolean(x % 2), [['a', 'a'], ['b', 'b']]) // should throw an error
validate((x: number) => x % 2 === 0, [[1, 2, 3]]); // should throw an error
function validate<K>(validationFunc: (...args: (K extends Array<infer T> ? T : K)[]) => boolean, validationArgs: K[]): boolean {
let res: boolean;
for (const validationArg of validationArgs) {
if (Array.isArray(validationArg)) {
res = validationFunc(...validationArg);
} else {
// res = validationFunc(validationArg);
res = (validationFunc as (args: K) => boolean)(validationArg);
}
if(!res)
return false;
}
return true
}
注释行在参数处抛出错误:the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[] ? T : K'.ts(2345)
,而转换版本有效,并且不会抛出任何错误。
如 this playground.
为什么 typescript 无法推断,在这一行中,K
不能属于 Array<any>
类型,因此允许传递给验证函数?
语义上:
如果第二个参数是 K[]
类型,函数需要接受 K
作为单个参数。
如果第二个参数是 K[][]
类型,函数需要接受 K
.
例如
validate((x: number) => x%2, [1, 2, 3])
应该可以
validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']])
应该可以
validate((x: number) => x%2, ['a', 'b'])
应该抛出错误
validate((x: number) => x%2, [['a', 'a'], ['b', 'b']])
应该抛出错误
编辑:
validate((x: number) => x % 2 === 0, [[1, 2, 3]])
也应该抛出错误,因为验证会破坏 number[][]
一次,并尝试用 number[]
(x: number) => boolean
我认为您不需要推断参数函数的类型。正如您所解释的那样,您的验证参数可以只是 K[] | K[][]
。
我在调用验证函数时也做了一个小改动 x % 2
应该包装在 Boolean()
中,否则 return 值将不正确。
function validate<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
let res: boolean;
for (const validationArg of validationArgs) {
res = validationFunc(validationArg);
if(!res)
return false;
}
return true
}
function simplified<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
return validationArgs.every((args) => validationFunc(args));
}
validate((x: number) => Boolean(x % 2), [[1], [2], [3]]) // should be ok
validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']]) // should be ok
validate((x: number) => Boolean(x % 2), [['a'], ['b']]) // should throw an error
validate((x: number) => Boolean(x % 2), [['a', 'a'], ['b', 'b']]) // should throw an error
validate((x: number) => x % 2 === 0, [[1, 2, 3]]); // should throw an error