【问题标题】:Typescript type T or function () => T usage打字稿类型 T 或函数 () => T 用法
【发布时间】:2021-05-06 23:52:55
【问题描述】:

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

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你可以写:

    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
    

    在原始版本中,arg 在 true 分支中被解析为 (() =&gt; T) | (T &amp; Function)。 TS 显然无法识别这种联合函数类型,即两个组成部分 都是 可调用的。至少在上面的版本中,编译器很清楚你可以在函数检查之后调用arg

    对于 TypeScript 存储库中的这种情况,create a github issue 可能也值得 - 在我看来 T &amp; Function 应该 代表一些(宽)类型的函数。

    【讨论】:

    • 这是一个聪明的技巧,谢谢。我创建了一个问题here
    • 嘿,GitHub 问题说这个技巧是错误,并且原始行为是正确的(这部分是有道理的,因为如果 T 本身就是像 (x: string) =&gt; number 这样的函数类型,那么它拨打arg()不安全。
    • 这个问题也是saysinstanceof Function 一起工作是一个很好的解决方法
    【解决方案2】:

    使用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 描述的。

    【讨论】:

      【解决方案3】:

      我尝试了一种与已接受答案不同的方法,即禁止 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

      【讨论】:

        猜你喜欢
        • 2018-04-27
        • 2020-11-25
        • 2022-06-13
        • 2020-05-05
        • 2021-11-10
        • 2021-05-20
        • 2020-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多