您可以在this playground中看到一个演示。
我制作了一个简单的泛型类型,可以表示变量或返回变量的函数。但是,不幸的是,它不适用于典型的typeof arg === 'function'
检查。它将产生以下错误:
This expression is not callable.
Not all constituents of type '(() => T) | (T & Function)' are callable.
Type 'T & Function' has no call signatures.
有没有不用类型保护功能就可以工作的方法?
type Initializer<T> = T | (() => T)
function correct(arg: Initializer<string>) {
return typeof arg === 'function' ? arg() : arg
}
function wrong<T>(arg: Initializer<T>) {
return typeof arg === 'function' ? arg() : arg // error here
}
const isFunction = (arg: any): arg is Function => typeof arg === 'function'
function correct_2<T>(arg: Initializer<T>) {
return isFunction(arg) ? arg() : arg
}
答案 0 :(得分:2)
您可以写:
GetQuestions
在原始版本中,type Initializer<T> = T extends any ? (T | (() => T)) : never
function correct<T>(arg: Initializer<T>): T {
return typeof arg === 'function' ? arg() : arg // works
// arg is Initializer<T> & Function in the true branch
}
const r1 = correct(2) // const r1: 2
const r2 = correct(() => 2) // const r2: number
在true分支中解析为arg
。对于这种联合函数类型,TS显然无法识别,两个组成部分 都是可调用的。至少在以上版本中,对于编译器来说,很明显,您可以在功能检查后调用(() => T) | (T & Function)
。
在这种情况下,在TypeScript存储库中,create a github issue也值得-我认为arg
应该代表某种(广泛的)功能类型。
答案 1 :(得分:2)
我尝试了一种与接受的答案不同的方法,通过禁止 T(预期解析值)作为函数。它似乎适用于大多数用例,除非您尝试从初始化程序生成函数。
type Initializer<T> = T extends Function ? never : T | (() => T);
function foo<T>(r: Initializer<T>): T {
return typeof r === 'function' ? r() : r;
}
const valOK = foo('2');
const funOK = foo(() => 4);
const funError = foo((a: number, b: number) => a + b); // Expected error
答案 2 :(得分:0)
使用 instanceof Function
检查 arg
是否可调用效果很好:
type Initializer<T> = T | (() => T)
function fixed<T>(arg: Initializer<T>) {
// Instead of using `typeof`:
// return typeof arg === 'function' ? arg() : arg // error here
// use `instanceof`
return arg instanceof Function ? arg() : arg
}
这最初是由 kentcdodds on a GitHub issue related to this 描述的。