在打字稿中,为什么| &&运算符在功能类型上使用时会翻转其含义?
在此代码中,example1
和example2
使我感到困惑:
type F1 = (a: string, b:string) => void;
type F2 = (a: number, b:number) => void;
// re: example 1 and 2:
// After the =, | means "or" and & means "and"
// Before the =, & means "or" and | means "and"
const example1: F1 & F2 = (a: string | number, b: string | number) => {}
example1("Hello", "World")
example1(1, 2)
// example1("Hello", 2) // Error! number is not assignable to parameter of type string... (and vice versa)
const example2: F1 | F2 = (a: string | number, b: string | number) => {}
// example2("Hello", "World") // Error! Argument of type string is not assignable to parameter of type never
// example2(1, 2) // Error! Argument of type number is not assignable to parameter of type never
// example2("Hello", 2) // Error! Argument of type string is not assignable to parameter of type never
// re: example 3,4,5:
// Before the =, | means "or"
// const example3: number | string = true // Error! Type Boolean is not assignable to type number | string
const example4: number | string = 1
const example5: number | string = "foo"
// re: example 6,7
// Before the =, & means "and"
// const example6: {a: string} & {b: number} = {a: "foo"} // Error! Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: number; }'.
// Property 'b' is missing in type '{ a: string; }' but required in type '{ b: number; }'.
const example7: {a: string} & {b: number} = {a: "foo", b: 5}
对我来说似乎就像example1
和中的操作员example2
(在=
之前)的行为与其他方式相反。这是我期望这些示例可以正常工作的方式:
const example1: F1 & F2 = (a: string | number, b: string | number) => {}
// example2("Hello", "World") // Error! Argument of type string is not assignable to parameter of type never
// example2(1, 2) // Error! Argument of type number is not assignable to parameter of type never
// example2("Hello", 2) // Error! Argument of type string is not assignable to parameter of type never
const example2: F1 | F2 = (a: string | number, b: string | number) => {}
example1("Hello", "World")
example1(1, 2)
// example1("Hello", 2) // Error! number is not assignable to parameter of type string... (and vice versa)
如果example1
甚至没有编译,这也对我来说也很有意义,因为“字符串类型!==数字类型类型”。
为什么这种工作不像预期?
In this code, example1
and example2
are confusing me:
type F1 = (a: string, b:string) => void;
type F2 = (a: number, b:number) => void;
// re: example 1 and 2:
// After the =, | means "or" and & means "and"
// Before the =, & means "or" and | means "and"
const example1: F1 & F2 = (a: string | number, b: string | number) => {}
example1("Hello", "World")
example1(1, 2)
// example1("Hello", 2) // Error! number is not assignable to parameter of type string... (and vice versa)
const example2: F1 | F2 = (a: string | number, b: string | number) => {}
// example2("Hello", "World") // Error! Argument of type string is not assignable to parameter of type never
// example2(1, 2) // Error! Argument of type number is not assignable to parameter of type never
// example2("Hello", 2) // Error! Argument of type string is not assignable to parameter of type never
// re: example 3,4,5:
// Before the =, | means "or"
// const example3: number | string = true // Error! Type Boolean is not assignable to type number | string
const example4: number | string = 1
const example5: number | string = "foo"
// re: example 6,7
// Before the =, & means "and"
// const example6: {a: string} & {b: number} = {a: "foo"} // Error! Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: number; }'.
// Property 'b' is missing in type '{ a: string; }' but required in type '{ b: number; }'.
const example7: {a: string} & {b: number} = {a: "foo", b: 5}
To me it seems like the operators in example1
and example2
(before the =
) are behaving the opposite way from the others. Here's how I would expect these examples to work:
const example1: F1 & F2 = (a: string | number, b: string | number) => {}
// example2("Hello", "World") // Error! Argument of type string is not assignable to parameter of type never
// example2(1, 2) // Error! Argument of type number is not assignable to parameter of type never
// example2("Hello", 2) // Error! Argument of type string is not assignable to parameter of type never
const example2: F1 | F2 = (a: string | number, b: string | number) => {}
example1("Hello", "World")
example1(1, 2)
// example1("Hello", 2) // Error! number is not assignable to parameter of type string... (and vice versa)
It would also make sense to me if example1
didn't even compile, since "type of string !== type of number".
Why isn't this working as expected?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用这些类型,
以及
example1
的此声明,example1
已声明了类型f1& f2
,因此可以称为两个字符串的函数,也可以作为两个数字的函数。但是,不能用两个参数的混合来调用。您分配的函数值可以,但是f1& F2
严格来说是的超级类型(a:string | number,b:string | number)=> void
,因此,当我们分配给具有静态supertype的变量时,我们丢失了信息,就像将数字3
分配给类型未知
的变量一样丢失信息。example2
的类型是可以使用String
gragonments 或来调用的任何一个功能的类型/代码>参数。您分配给它的功能都可以使用任何一个,因此分配很好。但是我们永远无法称呼此功能。根本。我们将不得不通过两个参数,其中这些参数与
f1
和f2
签名兼容。f1
期望字符串
和f2
期望号码
,因此我们需要传递既是String and of String and code 一个数字,即字符串&数字
。和字符串&编号
是从不
,空类型。|
在第二个功能中变成&
的原因是由于一个小东西,称为方差。函数参数是违反的,因此((a:a1)=> b1)& ((a:a2)=> b2)
等于(a:a1 | a2)=> B1& B2
和((A:A1)=> B1)| ((a:a2)=> b2)
等于(a:a1& a2)=> B1 | B2
。您可以阅读Wikipedia页面以获取有关其背后数学的更多详细信息,或者写出“和”或“类型”的意思并遵循您的直觉。With these types,
and this declaration of
example1
,example1
has declared typeF1 & F2
, so it can be called both as a function of two strings and as a function of two numbers. But it can't be called with a mix of the two arguments. The function value you assigned to it could, butF1 & F2
is strictly a supertype of(a: string | number, b: string | number) => void
, so we lost information when we assigned to a variable with a static supertype, in the same way that assigning the number3
to a variable of typeunknown
loses information.The type of
example2
is the type of either functions which can be called withstring
arguments or those that can be called withnumber
arguments. The function you're assigning to it can be called with either, so the assignment is fine.But we can never call this function. At all. We would have to pass it two arguments, where those arguments are compatible with both the
F1
andF2
signatures.F1
expectsstring
andF2
expectsnumber
, so we need to pass something that's both a string and a number, i.e.string & number
. Andstring & number
isnever
, the empty type.The reason the
|
turns into an&
in that second function is due to a little thing called variance. Function arguments are contravariant, so((a: A1) => B1) & ((a: A2) => B2)
is equal to(a: A1 | A2) => B1 & B2
and((a: A1) => B1) | ((a: A2) => B2)
is equal to(a: A1 & A2) => B1 | B2
. You can read that Wikipedia page for more details on the math behind it, or write out what the "and" and "or" type means and follow your intuition.的确,当将这些功能组合在一起时,情况可能会使函数类型的参数混淆。
@bishwajitjha试图用集合理论解释它并不是完全错误的,即使简单的图可能就足够了。
交叉点
f1& f2
函数类型的f2因此,它对应于a :
example1(“ Hello”,“ world”)
),example1(1) ,2)
),example1(“ Hello”,2)
),更容易查看Typescript如何处理
f1& f2
交叉点作为超负荷,如果返回类型:联合
f1 | f2
函数类型的f2
示例2
可以只是F1,也可以是F2,也可以是两者的过载。因为联盟没有提供任何进一步的信息,所以当我们尝试使用示例2
时,我们必须同时考虑所有这些可能性 : https://www.typescriptlang.org/docs/handbook/handbook/handbook/2/everyday-day-types 。字符串
,也可以是号码
(上一节),因此两个参数必须同时
同时字符串
和号码
,即String&数字
。不幸的是,这是 /a>如@silviomayolo所述。请注意,我们仍然可以对
示例2
函数进行“有效”调用:至少,返回类型(如果有一个)遵循直觉:
分配的实际函数呢?
不幸的是,即使我们分配了一个可以接受更多不同参数类型的实际函数(甚至可能是
boolean
,null
,一个任意类型等的工会;它可以以一种或另一种方式称为F1,也可以称为F2),我们通过明确指定example2
的类型而失去了更宽容的行为。如果是
f1 | f2
联合,如果我们分配了 narrawer 类型,例如(a:string,b:string)=> {}
:这里的TypeScript会遵循分配,并推断我们有一个较窄的类型(如代码>示例7 ?
正如 @silviomayolo的评论所指出的那样,这些示例表明了 sigsment 的预期。
进一步,我们也可以描述他们的用法,但是它们仍然接近直觉:
组合功能类型的参数确实具有误导性。
TypeScript Playground
It is true that the situation may be confusing regarding the arguments of types of function, when these functions are combined together.
@Bishwajitjha is not totally wrong in trying to explain it with the Set theory, even though simple diagrams may be enough.
Intersection
F1 & F2
of function typesexample1
function can be called both as F1 and as F2. Therefore it corresponds to a TypeScript function overload:example1("Hello", "World")
),example1(1, 2)
),example1("Hello", 2)
)It is even easier to see how TypeScript handles the
F1 & F2
intersection as an overload, if they had return types:Union
F1 | F2
of function typesHere it is more complex, because it does not match a specific TypeScript construct.
example2
may be just an F1, or just an F2, or an overload of both. Because the union does not provide any further information, when we try usingexample2
, we must account for all these possibilities simultaneously: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#working-with-union-typesstring
number
string
or both asnumber
(previous section)Therefore both arguments must be at the same time
string
andnumber
, i.e.string & number
. Which is unfortunatelynever
as described by @SilvioMayolo.Note that we could still have a "valid" call to
example2
function:At least, the return type (if they had one) follows the intuition:
What about the actual function that was assigned?
Unfortunately, even though we assign an actual function that can accept more diverse argument types (it could even have been unions with
boolean
,null
, an arbitrary type, etc.; provided that it can be called one way or another as an F1, or alternatively as an F2), we lose the more tolerant behaviour by explicitly specifying the type ofexample2
.In the case of
F1 | F2
union, the situation would have been different if we had assigned a narrower type instead, e.g.(a: string, b: string) => {}
: here TypeScript would have followed the assignment, and inferred that we have a narrower type (as exactly described in https://www.typescriptlang.org/docs/handbook/2/narrowing.html#assignments)What about
example3
toexample7
?As pointed out by @SilvioMayolo's comment, these examples show how assignment is as expected.
Going further, we could describe their usage as well, but they would still be close to intuition:
Only arguments of combined function types are really misleading.
TypeScript Playground
由于类型没有赌注集,因此所有这些都遵循集合理论。
首先,让我们了解类型系统中
&
的关键行为。{a:'数字'}& {b:'string'} => {a:'number',b:'string'}
添加了两种成分类型,因为它们是独立的类型。
请记住这一点,让我们尝试证明这种行为,以及
f1& F2
和f1 | F2
As types are nothing bet sets, It all follows the Set theory.
First, let's understand a crucial behavior of
&
in type system.{ a: 'number' } & { b: 'string' } => { a: 'number', b: 'string' }
Both of the constituents types got added as they were independent types.
Keeping this in mind, let's try to prove this behavior and what should be the equivalent result of
F1 & F2
andF1 | F2