打字稿:如何解释扩展和函数类型之间的这种交互

问题描述 投票:4回答:1

示例1对我来说非常有意义

type X = (1 | 2 | 3) extends (infer I) ? [I] : never;

// X = [1 | 2 | 3]

示例2我不知道为什么类型变量现在相交

type X = (
    ((_: 1) => void) | ((_: 2) => void) | ((_: 3) => void)
) extends ((_: infer I) => void) ? [I] : never;

// X = [1 & 2 & 3]

我的猜测是与此有一些关系/相似之处:

type X = { x: number } | { y: number } | { z: number };
type Y = keyof X;

// Y = x & y & z

但是,我无法说服自己从第一原则上理解它。很想知道如何解释这一点。

typescript types type-systems
1个回答
4
投票

当引入type inference from conditional types时,它在发行说明中得到了解释。它是联合还是交集取决于推断类型的variance。直观地说,如果一个类型被推断为几个值的公共类型,它可以是它们中的任何一个(并集),但如果它被推断为多个函数的参数类型,则它们中的任何一个(交集)都必须是可接受的。

从发行说明中引用:

以下示例演示了共变量位置中相同类型变量的多个候选项如何导致联合类型被推断:

type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>;  // string
type T11 = Foo<{ a: string, b: number }>;  // string | number

同样,反变量位置中相同类型变量的多个候选者会导致交叉类型被推断:

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

进一步的讨论可以在PR implementing这个功能中找到。

作为旁注,它可以实现像union to intersection type conversion这样的一些很酷的技巧。

© www.soinside.com 2019 - 2024. All rights reserved.