typescript - 为什么在泛型类型上添加约束会改变推理行为?

标签 typescript typescript-generics

考虑以下示例:

function identity<T>(arr: T[]) { return arr }

identity(["a", "b"])

在这里,泛型类型 T 被推断为 string,这对我来说很有意义。

但是如果在T上加了约束(如下图),那么T会被推断为"a"| “b”,为什么?

function identity<T extends string>(arr: T[]) { return arr }

identity(["a", "b"])

最佳答案

我学到了一些东西可以分享。这不是一个明确的答案,但值得注意:

什么时候加宽类型参数,来自"a"string

https://github.com/microsoft/TypeScript/pull/10676

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.

类型参数T在以下情况下扩大:

  • T没有约束
  • 或其约束不包括原始类型或字面量类型

加宽
<T>(arr:T[])没有约束,所以类型会变宽。 'a' = string

无约束版本是如此通用,TS 没有对如何处理字面量做出太多假设。

未加宽
<T extends string>(arr:T[])具有原始约束且未加宽。

由于受限版本不太通用,因此它保留了它们。请参阅 PR,了解通常希望尽可能多地保留文字。

这也是一个有趣的花絮:

In cases where literal types are preserved in inferences for a type parameter (i.e. when no widening takes place), if all inferences are literal types or literal union types with the same base primitive type, the resulting inferred type is a union of the inferences. Otherwise, the inferred type is the common supertype of the inferences, and an error occurs if there is no such common supertype.

T 的所有推导都是相同基本原始类型 ( "a" ) 的文字类型 ( "b" , string )。

const fn = <T extends string>(arr:T[]) => arr
fn(['a', 'b'])  // ('a' | 'b')[]

如果推断不是文字类型,则推断类型是公共(public)父类(super class)型,string .

const fn = <T extends string>(arr:T[]) => arr
fn(['a' as string, "b"]) // widened to common supertype `string` 

一般来说,TS 会为给定的输入推断出“最佳”类型。这个函数恰好将字符串文字(作为不可变表达式)传递给 identity ,其返回类型为 T[]谁的Tstring 约束.如果它可以保留文字,它就会保留。

您可以看到有大量场景(从该 PR 粘贴),在这些场景中推理可以保留文字,而在哪些地方不能。

我没有关于哪种推理规则组合具体启用此行为的答案,但通常, typescript 会 typescript ,并且通常会尝试产生我们想要的输出。

关于typescript - 为什么在泛型类型上添加约束会改变推理行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73669925/

相关文章:

javascript - 重置表单自定义对象时,开始和结束更改为 null

typescript 根据先前参数的值推断可能的对象键?

typescript - 我可以根据参数更改返回类型吗

typescript - TS - 如何对泛型类型内的类型值执行字符串函数

javascript - typescript 类不接受参数类型

typescript - 如何在 typescript 中导出接口(interface)集合

Angular4 如何知道 ViewChild 何时被重置

javascript - 播种时未找到 "entity"的元数据

typescript - Typescript 中命名元组的通用名称是什么?

typescript - 如何允许 Typescript Generic 参数具有默认值