将类型声明与条件类型合并

时间:2019-05-09 23:43:00

标签: typescript

在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,并且将需要进行手动强制转换。

Playground Example

我希望ConditionalFn<string | number>解析为Fn<string> | Fn<number>,然后进一步解析为Fn<string | number>


Follow up

为什么Improved behavior for calling union types 示例中的f变量要求参数类型有交集? 我认为这是我困惑的根本原因。因为它会在没有任何交集的情况下将参数类型强制为any

1 个答案:

答案 0 :(得分:3)

您正在使用的条件类型为distributive,并按预期将ConditionalFn<string | number>扩展为Fn<string> | Fn<number>。但是Fn<string> | Fn<number> 不可分配给 Fn<string | number>。这些是完全不同的类型。

Fn<string | number>是一种非常特殊的功能;可以接受stringnumber参数的一个。它是一个单一的函数,它说“我不在乎参数是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版开始就支持它。

好的,希望能有所帮助;祝你好运!