为什么 Typescript 需要 infer 关键字?
Why is the infer keyword needed in Typescript?
为什么 Typescript 的人创建了 infer
关键字?
根据 documents,这是您将如何使用它的示例:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
我不明白为什么需要这个。为什么不能只是:
type ReturnType<T> = T extends (...args: any[]) => R ? R : any;
为什么这行不通?为什么需要 infer
关键字?
考虑以下代码:
interface Example {
foo: string
}
type GenericExample<T> = T extends Examlep ? 'foo' : 'bar';
这段代码应该导致编译错误,因为Examlep
拼写错误;没有名为 Examlep
的类型,显然程序员打算在这里写 Example
。
现在假设在条件类型的 extends
子句中不需要 infer
关键字。那么上面的代码就不会报编译错误了;它会看到没有名为 Examlep
的类型,推断它是什么类型,然后(因为 Examlep
没有约束)观察 T
确实扩展了 Examlep
for推断的类型。
在那种情况下,GenericExample<T>
总是 是 'foo'
而不管 T
是什么,并且不会有编译错误将错误告知程序员。这对编译器来说是错误的,几乎所有时候。
使用 infer
,编译器确保您已明确声明所有类型变量 :
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // T1 is { b: string; }
这里我们在MyType
中声明了一个new类型变量R
,其中gets inferred来自T
.
(请注意,infer
总是在 conditional type 的 extends
子句中使用。)
现在使用未声明的类型参数会导致编译错误:
type MyType2<T> = T extends R2 ? R2 : never; // error, R2 undeclared
如果没有 infer
,编译器将不知道,如果你想引入一个额外的类型变量 R2
来推断(见第一种情况),或者如果 R2
只是一次意外输入 error/typo。 infer
存在是为了消除这种歧义。
更准确地说,编译器会检查,如果 T
is assignable 到 R
,当 infer
被省略时:
type R = { a: number }
type MyType3<T> = T extends R ? R : never; // compare T with type R
type T2 = MyType2<{b: string}> // T2 is never
请注意,infer R
隐藏了同名类型声明的类型引用 R
:
type R = { a: number }
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // { b: string; }
infer 关键字允许您从条件类型中的另一个类型推导出一个类型。这是一个例子:
type UnpackArrayType<T> = T extends (infer R)[] ? R: T;
type t1 = UnpackArrayType<number[]>; // t1 is number
UnpackArrayType 是一种条件类型。它被读作“如果 T 是 (infer R)[] 的子类型,return R。否则,return T”。
对于类型别名 t1,UnpackArrayType 中的条件为真,因为 number[] 与 (infer R)[] 匹配。作为推断过程的结果,类型变量 R 被推断为数字类型,并且 return 从 true 分支。 Infer 是为了告诉编译器在 UnpackArrayType 的范围内声明了一个新的类型变量 R。
type t2 = UnpackArrayType<string>; //t2 is string
对于 t2 ,UnpackArrayType 中的条件为 false,因为字符串类型与 (infer R)[] 不匹配,因此它被 returned 为字符串。
有关更多信息,请查看这篇文章。
https://javascript.plainenglish.io/typescript-infer-keyword-explained-76f4a7208cb0?sk=082cf733b7fc66228c1373ba63d83187
我是这样想的:
infer X
替换 any
.
要使用上面的例子,
type UnpackArrayType<T> = T extends any[] ? T[number]: T;
->
type UnpackArrayType<T> = T extends (infer R)[] ? R: T;
X
声明为新类型,同时捕获
X
现在可以用在条件的 true/false
部分。
为什么 Typescript 的人创建了 infer
关键字?
根据 documents,这是您将如何使用它的示例:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
我不明白为什么需要这个。为什么不能只是:
type ReturnType<T> = T extends (...args: any[]) => R ? R : any;
为什么这行不通?为什么需要 infer
关键字?
考虑以下代码:
interface Example {
foo: string
}
type GenericExample<T> = T extends Examlep ? 'foo' : 'bar';
这段代码应该导致编译错误,因为Examlep
拼写错误;没有名为 Examlep
的类型,显然程序员打算在这里写 Example
。
现在假设在条件类型的 extends
子句中不需要 infer
关键字。那么上面的代码就不会报编译错误了;它会看到没有名为 Examlep
的类型,推断它是什么类型,然后(因为 Examlep
没有约束)观察 T
确实扩展了 Examlep
for推断的类型。
在那种情况下,GenericExample<T>
总是 是 'foo'
而不管 T
是什么,并且不会有编译错误将错误告知程序员。这对编译器来说是错误的,几乎所有时候。
使用 infer
,编译器确保您已明确声明所有类型变量 :
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // T1 is { b: string; }
这里我们在MyType
中声明了一个new类型变量R
,其中gets inferred来自T
.
(请注意,infer
总是在 conditional type 的 extends
子句中使用。)
现在使用未声明的类型参数会导致编译错误:
type MyType2<T> = T extends R2 ? R2 : never; // error, R2 undeclared
如果没有 infer
,编译器将不知道,如果你想引入一个额外的类型变量 R2
来推断(见第一种情况),或者如果 R2
只是一次意外输入 error/typo。 infer
存在是为了消除这种歧义。
更准确地说,编译器会检查,如果 T
is assignable 到 R
,当 infer
被省略时:
type R = { a: number }
type MyType3<T> = T extends R ? R : never; // compare T with type R
type T2 = MyType2<{b: string}> // T2 is never
请注意,infer R
隐藏了同名类型声明的类型引用 R
:
type R = { a: number }
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // { b: string; }
infer 关键字允许您从条件类型中的另一个类型推导出一个类型。这是一个例子:
type UnpackArrayType<T> = T extends (infer R)[] ? R: T;
type t1 = UnpackArrayType<number[]>; // t1 is number
UnpackArrayType 是一种条件类型。它被读作“如果 T 是 (infer R)[] 的子类型,return R。否则,return T”。
对于类型别名 t1,UnpackArrayType 中的条件为真,因为 number[] 与 (infer R)[] 匹配。作为推断过程的结果,类型变量 R 被推断为数字类型,并且 return 从 true 分支。 Infer 是为了告诉编译器在 UnpackArrayType 的范围内声明了一个新的类型变量 R。
type t2 = UnpackArrayType<string>; //t2 is string
对于 t2 ,UnpackArrayType 中的条件为 false,因为字符串类型与 (infer R)[] 不匹配,因此它被 returned 为字符串。 有关更多信息,请查看这篇文章。 https://javascript.plainenglish.io/typescript-infer-keyword-explained-76f4a7208cb0?sk=082cf733b7fc66228c1373ba63d83187
我是这样想的:
infer X
替换any
.
要使用上面的例子,
type UnpackArrayType<T> = T extends any[] ? T[number]: T;
->
type UnpackArrayType<T> = T extends (infer R)[] ? R: T;
X
声明为新类型,同时捕获X
现在可以用在条件的true/false
部分。