如何区分值和回调参数类型
How to differentiate between value and callback argument type
这个片段
function problem<T>(callback: T | (() => T)) : T {
return typeof callback === 'function' ? callback() : callback;
}
产生错误
This expression is not callable.
Not all constituents of type '(() => T) | (T & Function)' are callable.
Type 'T & Function' has no call signatures. ts(2349)
我花了一段时间才明白 Function
本身确实没有多大意义,因为我需要的是一个 无参数 函数。
在像 T = number
这样的特殊情况下,我可以简单地切换到测试 typeof callback === 'number'
并完成。但是,我需要一个通用的解决方案。
我愿意
- 限制
T
使其不包含函数,这(如我所愿)解决了问题。
- 或者对无参数函数进行运行时测试
我也愿意接受其他选择(我的主要目的是了解细节)。
有哪些可能性?
问题解释
与function myfun(s: string) {return s;}
和调用
problem(myfun);
类型 T = (s: string) => string
得到正确推断。不应该有像myfun()
这样的回调调用;相反,myfun
应该 returned。但是,它出错了,因为 typeof callback === 'function'
成立。
更新
我错误地假设 检查 callback instanceof Function
是 AFAIK 完全相同。
这是不同的,如 playground from the answer 所示。但是,添加
const myfun = (s: string) => s;
console.log(problem(myfun));
说出来
Argument of type '(s: string) => string' is not assignable to parameter of type 'string | (() => string)'.
Type '(s: string) => string' is not assignable to type '() => string'.ts(2345)
doAfter.ts(57, 21): Did you mean to call this expression?
这听起来像这行的错误
console.log(problem<(s: string) => string>(myfun));
编译并且没有类型歧义。但是,它不起作用,undefined
得到 returned 而不是 myfun
本身。
可能重复
链接问题的答案也没有解决我的问题:
- 普通
correct(myfun);
无法编译。
- 有效
correct<(s: string) => string>(myfun)
return 未定义。
我的第二个问题“(如何)对无参数函数进行运行时测试”也没有出现在潜在的重复问题中。
通过 instanceof
检查应该就足够了:
function problem<T>(callback: T | ((...args: any[]) => T)): T {
return callback instanceof Function ? callback() : callback;
}
const functionReturnsFromParameter = (s: string) => s;
const callbackReturnsString = () => 'Hello, World from function!';
const justAString = 'Hello, World from constant!'
console.log(problem(functionReturnsFromParameter))
console.log(problem(callbackReturnsString));
console.log(problem(justAString));
我明白你现在想做什么了。
目标:如果给定的回调不是无参数的,那么它应该被推断为T
类型并直接返回。如果它是无参数的,它应该被推断为 () => T
并被调用。为此,我建议使用 overload signature 像这样:
function problem<T extends () => any>(callback: T): ReturnType<T>;
function problem<T>(callback: T): T;
function problem(callback: unknown): unknown {
/* ... */
}
然后,在使用它时会推断出以下类型:
const test0 = problem("") // literal type: ""
const test1 = problem(() => "") // string
const test2 = problem((s: string) => s) // (s: string) => string
最后,您需要更改 problem
实现中的检查,以便它可以确定给定的回调是否为函数以及它是否接受参数。值得庆幸的是,在 javascript 中,函数有一个 .length
属性,指示所需参数的数量(对可变函数和默认参数有警告)。所以:
return callback instanceof Function && !callback.length ? callback() : callback;
应该可以。
这个片段
function problem<T>(callback: T | (() => T)) : T {
return typeof callback === 'function' ? callback() : callback;
}
产生错误
This expression is not callable.
Not all constituents of type '(() => T) | (T & Function)' are callable.
Type 'T & Function' has no call signatures. ts(2349)
我花了一段时间才明白 Function
本身确实没有多大意义,因为我需要的是一个 无参数 函数。
在像 T = number
这样的特殊情况下,我可以简单地切换到测试 typeof callback === 'number'
并完成。但是,我需要一个通用的解决方案。
我愿意
- 限制
T
使其不包含函数,这(如我所愿)解决了问题。 - 或者对无参数函数进行运行时测试
我也愿意接受其他选择(我的主要目的是了解细节)。
有哪些可能性?
问题解释
与function myfun(s: string) {return s;}
和调用
problem(myfun);
类型 T = (s: string) => string
得到正确推断。不应该有像myfun()
这样的回调调用;相反,myfun
应该 returned。但是,它出错了,因为 typeof callback === 'function'
成立。
更新
我错误地假设 检查 callback instanceof Function
是 AFAIK 完全相同。
这是不同的,如 playground from the answer 所示。但是,添加
const myfun = (s: string) => s;
console.log(problem(myfun));
说出来
Argument of type '(s: string) => string' is not assignable to parameter of type 'string | (() => string)'.
Type '(s: string) => string' is not assignable to type '() => string'.ts(2345)
doAfter.ts(57, 21): Did you mean to call this expression?
这听起来像这行的错误
console.log(problem<(s: string) => string>(myfun));
编译并且没有类型歧义。但是,它不起作用,undefined
得到 returned 而不是 myfun
本身。
可能重复
链接问题的答案也没有解决我的问题:
- 普通
correct(myfun);
无法编译。 - 有效
correct<(s: string) => string>(myfun)
return 未定义。
我的第二个问题“(如何)对无参数函数进行运行时测试”也没有出现在潜在的重复问题中。
通过 instanceof
检查应该就足够了:
function problem<T>(callback: T | ((...args: any[]) => T)): T {
return callback instanceof Function ? callback() : callback;
}
const functionReturnsFromParameter = (s: string) => s;
const callbackReturnsString = () => 'Hello, World from function!';
const justAString = 'Hello, World from constant!'
console.log(problem(functionReturnsFromParameter))
console.log(problem(callbackReturnsString));
console.log(problem(justAString));
我明白你现在想做什么了。
目标:如果给定的回调不是无参数的,那么它应该被推断为T
类型并直接返回。如果它是无参数的,它应该被推断为 () => T
并被调用。为此,我建议使用 overload signature 像这样:
function problem<T extends () => any>(callback: T): ReturnType<T>;
function problem<T>(callback: T): T;
function problem(callback: unknown): unknown {
/* ... */
}
然后,在使用它时会推断出以下类型:
const test0 = problem("") // literal type: ""
const test1 = problem(() => "") // string
const test2 = problem((s: string) => s) // (s: string) => string
最后,您需要更改 problem
实现中的检查,以便它可以确定给定的回调是否为函数以及它是否接受参数。值得庆幸的是,在 javascript 中,函数有一个 .length
属性,指示所需参数的数量(对可变函数和默认参数有警告)。所以:
return callback instanceof Function && !callback.length ? callback() : callback;
应该可以。