为什么 Typescript 推断“从不”而不是交叉类型?

twi*_*ort 4 typescript

给出以下示例:

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;
};

Run Code Online (Sandbox Code Playgroud)

链接到 ts-playgound

打字稿显示以下错误:

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'.
Run Code Online (Sandbox Code Playgroud)

这是清晰易懂的。但是,如果我向接口添加联合类型,如下所示:

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'.
Run Code Online (Sandbox Code Playgroud)

链接到 ts-playgound

我收到以下错误:

Type 'string | number' is not assignable to type 'never'.
  Type 'string' is not assignable to type 'never'.
Run Code Online (Sandbox Code Playgroud)

如果我使用交集类型,Typescript 会接受它,string & number & MultiType但它也接受never.

这对我来说似乎不一致。这可能是一个错误吗?

jca*_*alz 7

string & number等价于never,等价于string & number & (MultiType | null)。没有既是 astring又是 a 的number值,所以没有值满足string & numberstring & number & AnythingElse

现在后者显式地归约为,never因为它包含这些等价never类型的联合,这样离开真的很难看。具体来说,编译器在联合上分布交集,所以

string & number & ('x' | 'y' | null)
Run Code Online (Sandbox Code Playgroud)

变成

(string & number & 'x') | (string & number & 'y') | (string & number & null)
Run Code Online (Sandbox Code Playgroud)

这种类型对人们来说并不是特别有启发性,因此编译器会检查每个联合组成部分是否等价never并将类型减少到

never | never | never
Run Code Online (Sandbox Code Playgroud)

这只是

never
Run Code Online (Sandbox Code Playgroud)

如你所见。


那么为什么它string & number本身不会立即减少到never?那么最初的想法是,它会帮助人们明白的地方在他们的代码的bug是从哪里来的,因为string is not assignable to number是更有意义的是string is not assignable to never

不幸的是,虽然string & number就可以分配给它和从中分配的值而言,它是等效的never但在 TS3.5 及以下版本中,编译器并不总是将它们视为相同的,这令人困惑。

因此看起来,从 TS3.6 开始,空交叉点 likestring & numbernever显式减少到。一旦 TS3.6 发布,您上面的代码在两种情况下都将执行相同的操作,并且您将收到string | number is not assignable to never错误消息。


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