在TypeScript中通过条件类型传递类型的并集时,除去条件时返回的值不一致。
在给定类型联合的情况下,打字稿正确地将可能的参数合并到每个参数中。
type Fn<T> = (arg: T) => void
Fn<string | number> // (arg: string | number) => void
但是,当混合使用条件参数时,参数将被解析
type ConditionalFn<T> = T extends never ? Fn<T> : Fn<T>
ConditionalFn<string | number> // Fn<string> | Fn<number>
// That is equivalent to which is ((arg: string) => void | (arg: number) => void)
通常这不是问题。但是,当函数的类型设置为条件类型时,参数的所有类型都设置为any
,并且将需要进行手动强制转换。
我希望ConditionalFn<string | number>
解析为Fn<string> | Fn<number>
,然后进一步解析为Fn<string | number>
。
为什么Improved behavior for calling union types
示例中的f
变量要求参数类型有交集?
我认为这是我困惑的根本原因。因为它会在没有任何交集的情况下将参数类型强制为any
。
答案 0 :(得分:3)
您正在使用的条件类型为distributive,并按预期将ConditionalFn<string | number>
扩展为Fn<string> | Fn<number>
。但是Fn<string> | Fn<number>
不可分配给 Fn<string | number>
。这些是完全不同的类型。
Fn<string | number>
是一种非常特殊的功能;可以接受string
和number
参数的一个。它是一个单一的函数,它说“我不在乎参数是string
还是number
;我将接受其中任何一个”。
现在,只需要接受Fn<string>
类型的函数就可以接受string
,而只需要接受Fn<number>
类型的函数就可以number
。类型Fn<string> | Fn<number>
的函数是其中的一个 ,我们只是不知道哪个。这是一种不确定/模糊的函数类型。因此,实际上很难调用这种类型的函数(在TS3.3之前,如果没有类型声明,就无法调用它),因为我可以自信地将其传递给参数的唯一方法是给它一些参数既是string
又是number
;即string & number
。 TypeScript 3.3添加了support来调用带有交点的这种函数联合,这非常好……除了不存在类型string & number
的值;它等效于never
。因此,无法安全地调用类型为ConditionalFn<string | number>
的函数,这很可能是导致问题的原因。
只需重申一下这两种类型之间的区别:函数(a: number) => console.log(2-a)
是有效的Fn<string> | Fn<number>
(因为它是Fn<number>
),但它不是 有效的Fn<string | number>
(因为它不接受字符串)。
这确实会使人们感到困惑,因为函数类型相对于其参数类型在相反方向上变窄/变宽。这称为contravariance,并且TypeScript从2.6版开始就支持它。
好的,希望能有所帮助;祝你好运!