为什么仅当泛型 T 具有约束时才将其推断为文字类型?

Why generic T is inferred as a literal type only when it has a constraint?

请参阅以下代码段

declare function foo<T>(a: T): (b: T) => boolean;

foo(111)(222);       // T inferred as 'number'
foo('hello')('bye'); // T inferred as 'string'

declare function bar<T extends number | string>(a: T): (b: T) => boolean;

bar(111)(222);       // T inferred as '111'
bar('hello')('bye'); // T inferred as 'hello'

playground

如您所见,bar 函数将 T 的类型推断为文字类型(示例中的 '111''hello'),但在函数 foo 它们被推断为 numberstring,唯一的区别是约束。

奇怪的是,如果使用如下的盒装类型

declare function baz<T extends Number | String>(a: T): (b: T) => boolean;

然后 T 被推断为 numberstring,但其中一个是基本类型就足够了, T 被推断为字面量类型:

declare function brr<T extends Number | string>(a: T): (b: T) => boolean;

所以问题是: 为什么 foo('hello') 推断 Tstringbar('hello') 推断 T作为 'hello'?为什么它仅在 T 受到约束时发生(至少在本例中)?

有时,您需要为字符串文字 'hello' 推断出确切的文字类型 'hello'。有时,您需要为字符串文字 'hello'.

推断出更广泛的、非特定的 string 类型

规则 - 何时应该推断出确切的类型,何时应该扩大类型 - 经过了几次迭代,当前的实现 is presented here:

During type argument inference for a call expression the type inferred for a type parameter T is widened to its widened literal type if:

  • all inferences for T were made to top-level occurrences of T within the particular parameter type, and
  • T has no constraint or its constraint does not include primitive or literal types, and
  • T was fixed during inference or T does not occur at top-level in the return type.