为什么这段代码不能编译?
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]
~~~~~~~~~
有没有办法让它工作?
答案 0 :(得分:2)
试试这个
function update<T extends Thing>(obj: T, path: keyof T) {
obj[path] = obj[path]
}
答案 1 :(得分:1)
当您访问 obj[path]
时,它可能返回 A
或 B
,编译器不知道哪个,并且它(正确地)不允许赋值,除非所有满足约束:
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'];
}
所以这涵盖了为什么,但如果您想知道如何让编译器理解正确的类型,请查看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
有关工作示例,请参阅此 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)