让我们以example为例来自 TS 3.3 文档:
type Fruit = "apple" | "orange";
type Color = "red" | "orange";
type FruitEater = (fruit: Fruit) => number;
type ColorConsumer = (color: Color) => string;
type FnUnion = FruitEater | ColorConsumer
我想,以下函数可以分配给FnUnion
:
declare function foo(v: Fruit & Color): number | string
,正如有人告诉我的,函数在参数上是逆变的,在返回类型上是协变的。但请考虑以下内容:
declare let fn: FnUnion
declare function foo(v: Fruit & Color): number | string
declare function foo2(v: Fruit | Color): number
declare function foo3(v: Fruit | Color): string
fn = foo // error, why?
fn = foo2 // works
fn = foo3 // works
我对上述情况下联合函数的一般可分配性规则感兴趣。 foo2
和 foo3
可分配给 fn
。但为什么 foo
不可赋值呢?
我肯定会错过一些 TS 知识,感谢您的解答。谢谢! PS:这是一个sample .
最佳答案
需要明确的是,&
是交集,|
是并集。这意味着:
Fruit & Color //=> "orange"
Fruit | Color //=> "apple" | "orange" | "red"
这意味着:
type FnUnion = FruitEater | ColorConsumer
是接受所有水果的函数,或者是接受所有颜色的函数。
以下是该类型的有效用法:
const colorFn: FnUnion = (color: Color) => 'a color'
colorFn('red')
colorFn('orange')
const fruitFn: FnUnion = (fruit: Fruit) => 123
fruitFn('apple')
fruitFn('orange')
注意:必须是其中之一。它必须接受所有水果或它必须接受所有颜色。
但是,Fruit & Color
类型只能是'orange'
。因此,您将一个只能接受 'orange'
的函数分配给一个允许接受 'orange'|'red'
或'橙色'|'苹果'
。这意味着 'red'
或 'apple'
永远不能作为参数传递,其中 FnUnion
表示应允许其中之一.
因此 typescript 正确地提示类型不兼容。
此外,Typescript 知道联合体类型,还知道控制流中某些点的联合体成员的值。
当您像这样转换到 FnUnion
时:
const colorFn = ((color: Color) => 'a color') as FnUnion
您告诉 TS 它是联合体的哪个成员是不可知的,因为它不能再根据参数类型进行区分。
因此,似乎唯一安全的推论是这两种类型共有的一个参数。我意识到,这正是它不允许您直接分配的函数类型。
但我认为关键的区别是知道你的函数是工会的哪个成员。
// member known: ColorConsumer
const colorFn: FnUnion = (color: Color) => 'a color'
// member known: FruitEater
const fruitFn: FnUnion = (fruit: Fruit) => 123
// member unknown due to cast to less specific type.
// only common arguments are allowed,
// and only return types for those common arguments
const unknownFn: FnUnion = ((some: 'orange') => 'unknown') as FnUnion
// type is concretely known, but is not a match to any member.
const invalidFn: FnUnion = (some: 'orange') => 'invalid'
// ^ type error
FnUnion
表示它是其中之一,如果它不知道是哪一个,那么它是两者的交集。您想说的类型是已知的,它不是成员,而是两者的交集。这就是不兼容的地方。
但是正如您发现的那样,使用 as FnUnion
您可以使 typescript 忘记它对类型转换的了解。
所有这些意味着推断的某物类型并不总是它可以分配的类型。
关于typescript - 联合函数类型的可赋值性规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60440070/