[英]Why does Typescript infer 'never' instead of intersection type?
Given the following example: 给出以下示例:
interface Data {
name: string;
value: number;
}
const data :Data = {
name: 'name',
value: 1,
}
const updateValue = (key: keyof Data, value: string | number): void => {
data[key] = value;
};
link to ts-playgound 链接到ts-playgound
Typescript shows the following error: Typescript显示以下错误:
Type 'string | number' is not assignable to type 'string & number'.
Type 'string' is not assignable to type 'string & number'.
Type 'string' is not assignable to type 'number'.
Which is clear and understandable. 这是清楚易懂的。 However if I add a union type to the interface like so: 但是,如果我将一个联合类型添加到接口,如下所示:
type MultiType = 'x' | 'y';
interface Data {
name: string;
value: number;
multiType: MultiType | null;
}
const data :Data = {
name: 'name',
value: 1,
multiType: null,
}
const updateValue = (key: keyof Data, value: string | number): void => {
data[key] = value;
};
link to ts-playgound 链接到ts-playgound
I get the following error: 我收到以下错误:
Type 'string | number' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.
Typescript accepts it if I use the intersection type string & number & MultiType
but it also accepts never
. 如果我使用交集类型string & number & MultiType
但是它也接受never
,那么Typescript接受它。
This seems inconsistent to me. 这似乎与我不一致。 Is this maybe a bug? 这可能是个错误吗?
string & number
is equivalent to never
, and so is string & number & (MultiType | null)
. string & number
等于never
, string & number & (MultiType | null)
。 There are no values which are both a string
and a number
, so no values satisfy string & number
or string & number & AnythingElse
. 没有值既是string
又是number
,因此没有值满足string & number
或string & number & AnythingElse
。
Right now the latter explicitly reduces to never
because it contains unions of these equivalent-to- never
types, which is really ugly to leave like that. 现在,后者明确地减少到never
因为它包含这些等价到never
类型的联合,这样做真的很难看。 Specifically, the compiler distributes intersections over unions, so 具体来说,编译器将交叉点分布在联合上,因此
string & number & ('x' | 'y' | null)
becomes 变
(string & number & 'x') | (string & number & 'y') | (string & number & null)
That type isn't particularly enlightening to people, so the compiler checks that each of those union constituents is equivalent to never
and reduces the type to 这种类型对人们来说并不是特别有启发性,因此编译器会检查每个联合组成部分是否等同于never
,并将类型减少为
never | never | never
which is just 这只是
never
as you saw. 如你所见。
So why doesn't string & number
by itself get immediately reduced to never
? 那么为什么string & number
本身不会立即减少到never
? Well originally the idea was that it would help people understand where the bug in their code came from, since string is not assignable to number
is more enlightening that string is not assignable to never
. 最初的想法是,它可以帮助人们了解代码中的错误来自哪里,因为string is not assignable to number
更具启发性, string is not assignable to never
。
Unfortunately while string & number
is equivalent to never
in terms of what values are assignable to and from it, in TS3.5 and below the compiler doesn't always treat them the same, which is confusing. 不幸的是,虽然string & number
相当于 never
分配给它的值,但在TS3.5及更低版本中,编译器并不总是将它们视为相同,这是令人困惑的。
Therefore it looks like, starting in TS3.6, empty intersections like string & number
will be reduced to never
explicitly . 因此看起来,从TS3.6开始, 像string & number
这样的空交叉将never
明确地减少到 。 Once TS3.6 is released, your above code will act the same in both cases, and you'll get the string | number is not assignable to never
一旦TS3.6发布,你的上述代码在两种情况下的行为都相同,你将获得string | number is not assignable to never
string | number is not assignable to never
error. string | number is not assignable to never
错误。
Okay, hope that helps; 好的,希望有所帮助; good luck! 祝好运!
Two things : 两件事情 :
It's only logical that TypeScript doesn't accept string | number
TypeScript不接受string | number
合乎逻辑的 string | number
as type for your value
parameter, because all of the following : string | number
作为value
参数的类型,因为以下所有内容:
string | number
string | number
is not assignable to string
because number
is not assignable to string
in case the key
is 'name'
string | number
不能赋值给string
因为如果key
是'name'
则number
不能赋值给string
string | number
string | number
is not assignable to number
because string
is not assignable to number
in case the key
is 'value'
(both of there were already true in your first example) string | number
不能分配给number
因为如果key
是'value'
,则string
不能分配给number
(在第一个示例中,两者都已经为真)
string | number
string | number
is not assignable to MultiType | null
string | number
不能分配给MultiType | null
MultiType | null
because both number
and string
are not assignable to 'x' | 'y' | null
MultiType | null
因为number
和string
都不能赋值给'x' | 'y' | null
'x' | 'y' | null
'x' | 'y' | null
in case the key
is 'multiType'
如果key
是'multiType'
则'multiType'
'x' | 'y' | null
For some reason however, in your first example TypeScript simply stops on the first "wrong" case and gives you this error (Even though there are really two things wrong already). 但是出于某种原因,在你的第一个例子中,TypeScript只是在第一个“错误”的情况下停止并给你这个错误(即使已经有两个错误了)。
In the second case, you could have seen the same error message because the incompatibility of types is still there, it seems like the inference goes a little deeper and tells you that the problem is deeper than this. 在第二种情况下,您可能已经看到了相同的错误消息,因为类型的不兼容性仍然存在,似乎推理更深入并且告诉您问题比这更深。 As to why is the error message formatted like this, I don't really know and I guess it would require going deeper into how are things inferred by the compiler here. 至于为什么错误消息的格式是这样的,我真的不知道,我想这将需要更深入地了解编译器如何在这里推断出事物。 In the end, the compiler is right, but the error message could be clearer. 最后,编译器是正确的,但错误消息可能更清楚。
For your second question, the never
type documentation says : 对于您的第二个问题, never
类型的文档说:
The
never
type is a subtype of, and assignable to, every typenever
类型是每种类型的子类型,并且可分配给每种类型
So that's why you can specify your value
to be of type never
, and assign it to your data
. 因此,您可以将value
指定为never
类型,并将其分配给您的data
。 Because it will never happen. 因为它永远不会发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.