打字稿类型T或函数()=> T用法

时间:2020-03-28 06:40:50

标签: typescript

您可以在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
}

3 个答案:

答案 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

Playground link

答案 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 描述的。