为什么 Typescript 需要 infer 关键字?

Cod*_*ein 54 type-inference keyword typescript conditional-types

为什么 Typescript 的人会创建infer关键字?根据文档,这是您将如何使用它的示例:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
Run Code Online (Sandbox Code Playgroud)

我不明白为什么需要这样做。为什么不能只是:

type ReturnType<T> = T extends (...args: any[]) => R ? R : any;
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用?为什么infer需要关键字?

for*_*d04 45

使用infer,编译器确保您已显式声明所有类型变量。例如可以定义类型变量:

  • 在条件类型inferextends子句中之后?RT extends (...args: any[]) => infer R
  • 在类型声明的左侧?TReturnType<T> = ...
  • 作为映射类型的一部分?Ktype Mapped<T> = { [K in keyof T]: ... }

现在使用未声明的类型参数会导致编译错误。如果没有infer,编译器将不知道,如果您想引入一个额外的类型变量(比如R)来推断,或者R只是一个意外的输入错误/打字错误。

type R = { a: number }

type MyType<T> = T extends infer R ? R : never; // infer new variable R from T
type MyType2<T> = T extends R ? R : never; // compare T with above type R
type MyType3<T> = T extends R2 ? R2 : never; // error, R2 undeclared

type T1 = MyType<{b: string}> // T1 is { b: string; }
type T2 = MyType2<{b: string}> // T2 is never
Run Code Online (Sandbox Code Playgroud)

操场

  • `type MyType2&lt;T&gt; = ...` 是一个类型别名*声明*,其中泛型类型变量/参数 `T` 尚无法解析。稍后,我们通过在类型别名声明“type T2 = ...”中使用类型引用“MyType2&lt;{b: string}&gt;”,用“{b: string}”*实例化*“T”。现在,可以解析实际类型了。由于 `{b: string}` (`T` 的实例)不可[分配](https://www.typescriptlang.org/docs/handbook/type-compatibility.html)(这是“更具体的表达式”与“) 到 `R`(即“{a: number}”)相比,“T2”解析为“never”。希望这能让事情变得更清楚。 (2认同)

kay*_*ya3 44

考虑以下代码:

interface Example {
    foo: string
}

type GenericExample<T> = T extends Examlep ? 'foo' : 'bar';
Run Code Online (Sandbox Code Playgroud)

这段代码应该会导致编译错误,因为Examlep拼写错误;没有名为 的类型Examlep,显然程序员打算在Example这里编写。

现在假设条件类型inferextends子句中不需要关键字。那么上面的代码就不会给出编译错误;它会看到没有名为 的类型Examlep,推断它是什么类型,然后(因为Examlep没有约束)观察T确实扩展Examlep了推断的类型。

在这种情况下,GenericExample<T>始终'foo'无论什么样T的,并且就没有编译错误通知程序员有关的错误。对于编译器来说,这几乎在所有时间都是错误的。

  • `infer` 是说你知道你正在声明一个新类型(在条件类型的范围内) - 就像你必须编写 `var`、`let` 或 `const` 来告诉编译器你知道你正在声明一个新变量。 (8认同)
  • 它是一个类型变量,是一种类型。它不存在于条件类型的范围之外,因此它是新的。 (8认同)
  • 这是一个很棒的答案!确实很清楚为什么需要“infer”。 (4认同)
  • 好吧,基本上是有 `infer` 而不是一些全局的 `tsconfig` 设置来告诉编译器现在允许未定义的类型? (2认同)
  • 但“R”并不是一个新类型。这只是一个占位符 (2认同)

pea*_*nut 35

infer 关键字允许您从条件类型中的另一种类型推断出一种类型。这里\xe2\x80\x99s 是一个例子:

\n
type UnpackArrayType<T> = T extends (infer R)[] ? R: T;\ntype t1 = UnpackArrayType<number[]>; // t1 is number\n
Run Code Online (Sandbox Code Playgroud)\n

UnpackArrayType 是一种条件类型。它被读作 \xe2\x80\x9c 如果 T 是 (infer R)[] 的子类型,则返回 R。否则,返回 T\xe2\x80\x9d。

\n

对于类型别名 t1,UnpackArrayType 中的条件为 true,因为 number[] 与 (infer R)[] 匹配。作为推断过程的结果,类型变量 R 被推断为数字类型,并从 true 分支返回。Infer 的作用是告诉编译器在 UnpackArrayType 的范围内声明了一个新的类型变量 R。

\n
type t2 = UnpackArrayType<string>; //t2 is string\n
Run Code Online (Sandbox Code Playgroud)\n

对于 t2 , UnpackArrayType 中的条件为 false,因为字符串类型与(infer R)[] 不匹配,因此它以字符串形式返回。\n有关详细信息,请参阅本文。\n https: //javascript.plainenglish .io/typescript-infer-keyword-explained-76f4a7208cb0?sk=082cf733b7fc66228c1373ba63d83187

\n