为什么Typescript的开发者们创造了infer
关键字?
根据文档,以下是使用它的示例:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
我不明白为什么这是必要的。为什么不能只是这样:
type ReturnType<T> = T extends (...args: any[]) => R ? R : any;
为什么这段代码不起作用?为什么需要使用 "infer" 关键字?
为什么Typescript的开发者们创造了infer
关键字?
根据文档,以下是使用它的示例:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
我不明白为什么这是必要的。为什么不能只是这样:
type ReturnType<T> = T extends (...args: any[]) => R ? R : any;
infer
,编译器确保您已明确声明了所有类型变量。type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // T1 is { b: string; }
type MyType2<T> = T extends R2 ? R2 : never; // error, R2 undeclared
infer
,编译器就无法确定你是否想引入一个额外的类型变量R2
来进行推断(参见第一个情况),还是R2
只是一个意外的打字错误。infer
的存在就是为了消除这种歧义。infer
时,编译器会检查T
是否可分配给R
。type R = { a: number }
type MyType3<T> = T extends R ? R : never; // compare T with type R
type T3 = MyType3<{b: string}> // T3 is never
infer R
会覆盖同名类型声明R
的类型引用。type R = { a: number }
type MyType4<T> = T extends infer R ? R : never;
type T4 = MyType4<{b: string}> // { b: string; }
interface Example {
foo: string
}
type GenericExample<T> = T extends Examlep ? 'foo' : 'bar';
infer
的存在是为了替代一些全局的 tsconfig
设置,告诉编译器不允许 undefined 类型。 - CodyBugsteinR
不是一个新类型。它只是一个占位符。 - CodyBugsteininfer
。 - MEMarktype UnpackArrayType<T> = T extends (infer R)[] ? R: T;
type t1 = UnpackArrayType<number[]>; // t1 is number
UnpackArrayType是一个条件类型。它的解释是:“如果T是(infer R)[]的子类型,返回R。否则,返回T”。
对于类型别名t1,UnpackArrayType中的条件为true,因为number[]与(infer R)[]匹配。在推断过程的结果中,类型变量R被推断为number类型,并从true分支中返回。在UnpackArrayType的范围内声明了一个新的类型变量R,这就是infer的作用,告诉编译器需要声明一个新的类型变量R。
type t2 = UnpackArrayType<string>; //t2 is string
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
部分中使用。
MyType2
应该可以工作。T extends R
应该意味着任何扩展我们上面定义的R
的类型。你所说的“将T与上面的类型R进行比较”是什么意思? - CodyBugsteintype MyType2<T> = ...
是一个类型别名声明,其中泛型类型变量/参数T
无法被解析。稍后我们通过在类型别名声明type T2 = ...
中使用类型引用MyType2<{b: string}>
来实例化T
为{b: string}
。现在,实际类型可以被解析了。由于{b: string}
(T
的实例)不能被分配(这是“与之比较”的更具体表达方式)给R
- 它是{a: number}
-,因此T2
解析为never
。希望这样能让事情更清楚。 - ford04MyType2
可以工作。T
扩展了我们上面定义的R
应该意味着任何扩展R
的类型。”并不太有意义(取决于你对“工作”的理解)。泛型类型别名需要先为T
获取一些具体的东西,然后才能进一步解析。 - ford04type T3 = MyType3<{b: string}>
(MyType2<T>
是在声明时出现编译错误的情况)。 - ford04