【问题标题】:Inference in generic function parameters泛型函数参数中的推断
【发布时间】:2018-10-20 02:56:18
【问题描述】:

TypeScript 中的基本类型推断非常简单:

const bar = foo(); // bar: <type that foo returns>

考虑到泛型参数默认值为{},可以合理地预期下面的代码会导致类型错误,因为回调函数返回number而不是{}

function foo<T = {}>(callback: () => T): T {
    return callback();
}

let bar = foo(() => 1); // bar: number

但已知T是从回调返回值推断出来的,它是:

function foo<number>(callback: () => number): number

这究竟是如何发生的,这种行为是在哪里规定的?来自 TypeScript 开发人员的文档或解释中的引述将不胜感激。

是否可以强制T 为默认值({}&lt;T = ...&gt; 中指定的任何值)而不是在foo(() =&gt; 1) 调用中推断?在某些情况下,这可能是理想的行为。

如果 TypeScript 中有其他反直觉的推理案例,也欢迎提及。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    在某种程度上,你回答了你自己的问题:

    考虑到通用参数默认值为{}

    通过使用语法&lt;T = {}&gt;,您分配的是默认值,而不是要求。只有在 TypeScript 无法通过其他方式推断出T 的类型时才会使用默认值。

    如果您想明确限制T 可以采用的形式,您应该使用通用约束而不是默认约束。 (请参阅TypeScript Generics documentation 中的通用约束部分)

    例如,使用您提供的示例:

    function foo<T extends object>(callback: () => T): T {
      return callback();
    }
    
    let bar = foo(() => 1); // Type 'number' is not assignable to type 'object'
    

    您甚至可以使用&lt;T extends object = {}&gt; 在约束旁边提供默认值

    至于你有点不同的问题:

    是否可以强制 T 为默认值 [...] 并且不被推断

    是的,当您调用函数以覆盖推理时,您始终可以提供一个类型。例如:

    function foo<T extends object = {}>(callback: () => T): T {
      return callback();
    }
    
    interface User { name: string }
    const user: User = { name: 'Bob' };
    
    let bar = foo<{}>(() => user); // bar: {}
    

    即使我传递了 User 类型的 T,我还是显式声明了调用的泛型,并且输出将改用该泛型值。

    【讨论】:

    • 谢谢。这就是为什么我认为这违反直觉,因为没有什么可以 infer - 已经有 default 值了。我什至认为这是一个错误,但它看起来更像是一个功能。 TS中有太多应该凭经验推断出来的,这就是我要求参考的原因。 T extends 看起来我们走在正确的轨道上......但遗憾的是,如果允许将 T 明确指定为 foo&lt;number&gt;(...),这将不起作用,但对于 foo(...) 应坚持使用 {}。你有什么想法可以实现吗?
    • 您明确指定的任何泛型仍然必须符合泛型的约束。如果泛型输入为T extends object,则foo&lt;number&gt; 将出错,提示Type 'number' does not satisfy the constraint 'object'。你能解释一下你到底想要达到什么目的吗?如果您总是希望将其键入为 {},则不应使用泛型,而只需将返回类型设置为 {},尽管这似乎不是一个有用的场景。
    • 为了简单起见,我使用了{},因为它是默认参数值。假设 foo 处理错误,默认情况下 TErrorfoo(...) 调用应该限制为 Error 返回值。但是如果 T 被显式传递,则任何错误都可能发生,foo&lt;string&gt;(...)
    猜你喜欢
    • 1970-01-01
    • 2016-11-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 2020-01-23
    • 2016-12-05
    相关资源
    最近更新 更多