输入'A | B' 不可分配给类型 'A & B'

时间:2021-06-08 11:52:19

标签: typescript static-typing union-types

为什么这段代码不能编译?

type A = { n: number }
type B = { s: string }
type Thing = {
  a: A
  b: B
}
function update(obj: Thing, path: keyof Thing) {
  obj[path] = obj[path]
}

我希望赋值的双方都具有 A | B 类型,但 TypeScript 编译器失败:

error TS2322: Type 'A | B' is not assignable to type 'A & B'.
  Type 'A' is not assignable to type 'A & B'.
    Property 's' is missing in type 'A' but required in type 'B'.

10     obj[path] = obj[path]
       ~~~~~~~~~

有没有办法让它工作?

4 个答案:

答案 0 :(得分:2)

试试这个

function update<T extends Thing>(obj: T, path: keyof T) {
  obj[path] = obj[path]
}

答案 1 :(得分:1)

当您访问 obj[path] 时,它可能返回 AB,编译器不知道哪个,并且它(正确地)不允许赋值,除非所有满足约束:

type key = keyof Thing;
const keys: key[] = ['a', 'b'];

const path = keys[Math.round(Math.random())];
const thing: Thing = {
    a: {
        n: 3
    },

    b: {
        s: 'hi'
    }
};

const result = thing[path]; // A | B, compiler can't know which!

那么现在如果我使用路径来访问事物,我得到的是 A 还是 B?编译器无法知道,也无法在访问点缩小类型。你我都知道是一回事,但编译器无法证明。 funarg 也是如此。

如果你使用静态可知的东西,编译器允许赋值:

function update(obj: Thing) {
  obj.a = obj.a;
  obj['a'] = obj['a'];
}

Playground

所以这涵盖了为什么,但如果您想知道如何让编译器理解正确的类型,请查看this canonical answer

答案 2 :(得分:1)

发生这种情况是因为 Typescript 3.5 中引入了 changes 以提高索引访问类型的健全性。

<块引用>

当索引访问 T[K] 发生在类型关系的源端时,它解析为 T[K] 选择的属性的联合类型,但是当它发生在类型关系的目标端时,它现在解析为由 T[K] 选择的属性的交集类型。以前,目标端也会解析为联合类型,这是不合理的。

type A = { n: number }
type B = { s: string }
type Thing = { 
  a: A
  b: B
}

declare const thing: Thing

const key = 'a' as keyof Thing

let t = thing[key] // t has type A | B
t = { s: '' }      // we can `safely` assign it a value of type `B`
 
thing[key] = t     // and here things break

playground link


有关工作示例,请参阅此 answer

答案 3 :(得分:0)

您可以使用接受任何键的索引签名,其值为 import numpy as np import matplotlib.pyplot as plt array = np.arange(90) array = np.concatenate([array[:30], array[30:] + 180, array[60:] + 2 * 180 + 30]) plt.plot(array) 的交集。

adjusted = array - np.concatenate([[0], ((np.diff(array) >= 180).cumsum() * 180)])
plt.plot(adjusted)