简体   繁体   English

条件类型中的TypeScript类型推断

[英]TypeScript type inference in conditional types

I'm confused by how types are inferred in the following example 我对以下示例中的类型推断方式感到困惑

type RetType<T> = T extends (...args: (infer I)[]) => infer R ? [I, R] : any;
type X = (a: number, b: string) => void;
type Q = RetType<X>;

If you hover over the type of Q in the playground you will get [number & string, void] . 如果您将鼠标悬停在操场上的Q类型上,您将获得[number & string, void] It's confusing because I would expect I to be inferred as number | string 这令人困惑,因为我希望I被推断为number | string number | string (union) instead of number & string (intersection). number | string (union)而不是number & string (intersection)。

Does anyone understand why the input arguments are inferred as an intersection instead of a union? 有没有人理解为什么输入参数被推断为交集而不是联合?

TL;DR: Because whatever I is, it has to be assignable to all the arguments of the function type T . TL; DR:因为无论I是什么,它都必须可以赋值给函数类型T 所有参数。


This is because function arguments are contra-variant . 这是因为函数参数是反变量的 That just means that for one function to be used in place of another, its argument type must be the same or more general than the other's. 这只是意味着对于一个函数来代替另一个函数,它的参数类型必须与其他函数相同或更通用。 This is pretty obvious when you take a look at an example: 当你看一个例子时,这是非常明显的:

type f: (arg: string) => string;
type g: (arg: "foo") => string;

// f is assignable to g, since a function expecting
// to receive any string should have no problem accepting
// the specific string "foo".

// However, the reverse isn't true. You can't assign g to f,
// since g expects to receive exactly the string "foo" for its
// argument, but if it's used in place of f, it can receive any string.

In other words, f is assignable to g because g 's argument is assignable to f 's. 换句话说, f可赋值给g因为g的参数可赋值给f That reversal is the contra part. 这种逆转是对立面

So if T is a subtype of some mystery function type (...args: I[]) => R , argument contra-variance tells us that I must be assignable to the argument type of T . 因此,如果T是一些神秘功能类型的子类型(...args: I[]) => R ,参数禁忌方差告诉我们, I必须是可分配给参数类型的T

Thus, T extends (...args: (infer I)[]) => infer R tells typescript to infer some single type I such that I can be used in place of any argument of T . 因此, T extends (...args: (infer I)[]) => infer R告诉typescript推断某些单一类型I这样I就可以用来代替T任何参数。

So for your type X , it should be true that whatever I is, it must be assignable to both arguments. 所以对于你的类型X ,无论I是什么,它都应该是真的,它必须可以分配给两个参数。 Since the argument types are respectively number and string , we ask: what type is assignable to both of those? 由于参数类型分别是numberstring ,我们会问: 两种类型都可分配哪种类型?

Well, number & string . 好吧, number & string


*For more, you may be interested in reading about co and contra-variance . *有关更多信息,您可能有兴趣阅读co和contra-variance

This may not be the answer or explanation you're looking for, but this is called out in the docs : 这可能不是您正在寻找的答案或解释,但这在文档中提到

Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred: 同样,反变量位置中相同类型变量的多个候选者会导致交叉类型被推断:

 type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never; type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>; // string type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM