TypeScript中的联合类型赋值

TypeScript中的联合类型赋值,typescript,Typescript,有没有办法让这样的任务生效 type A = { a: string }; type B = { b: string }; const x = { AA: undefined as A | undefined, BB: undefined as B | undefined, } const name1 = "AA" const x1 = x[name1]; // type: A | undefined x[name1] = x1; const name2 = "AA" as "AA

有没有办法让这样的任务生效

type A = { a: string };
type B = { b: string };

const x = {
  AA: undefined as A | undefined,
  BB: undefined as B | undefined,
}

const name1 = "AA"
const x1 = x[name1]; // type: A | undefined
x[name1] = x1;

const name2 = "AA" as "AA"|"BB";
const x2 = x[name2]; // type: A | B | undefined
x[name2] = x2; //ERROR

//Type 'A | B | undefined' is not assignable to type '(A & B) | undefined'.
//  Type 'A' is not assignable to type 'A & B'.
//    Property 'b' is missing in type 'A' but required in type 'B'.
这是由于最近在TypeScript 3.5中引入了一个功能(有关更多信息,请参阅),该功能提高了写入时的可靠性。简而言之,您所做的只是安全的,因为您碰巧知道您正在将一个值写回刚刚从中读取的属性。但是编译器没有意识到这一点,因为您有意将属性键的类型扩展为联合。因此,
x2
的类型是
A | B |未定义的
,将该类型写回
x[name2]

const name2 = "AA" as "AA" | "BB";
let x2 = x[name2]; // type: A | B | undefined
x2 = { b: "okay" }; // works because x2 is of A | B | undefined
x[name2] = x2; // now this error makes sense, right?
在我看来,这里的问题是我所说的语言缺乏支持。您知道,
A | B | undefined
类型的两个联合类型表达式
x2
x[name2]
不是相互独立的。它们要么都是
A |未定义的
,要么都是
B |未定义的
。但是编译器无法表达这种依赖性。这里的解决方法通常涉及泛型、类型断言或代码复制


泛型:让编译器理解这一点是安全的一种方法是对泛型函数进行抽象,其中名称是泛型类型,扩展了
“AA”|“BB”

但允许这样做比不允许更有用


断言:另一种解决方法是通过a松开赋值的
x
类型,如:

相当于

type L = {
    a: string;
    b: number | boolean;
    c: number | boolean;
}    
因此,如果我在赋值之前将
{a:string;b:number;c:boolean}
类型的值加宽到
L
,我就可以毫无怨言地将
boolean
写入
b
并将a
number
写入
c
。当您执行这样的断言时,您需要小心不要对编译器撒谎,并将错误的值放在错误的属性中


重复:最后一个解决方法是手动引导编译器完成所有可能的操作。。。这是完全类型安全但冗余的:

const name5 = Math.random() < 0.5 ? "AA" : "BB";
if (name5 === "AA") {
  const x5 = x[name5];
  x[name5] = x5; // okay
} else {
  const x5 = x[name5];
  x[name5] = x5; // okay
}
const name5=Math.random()<0.5?“AA”:“BB”;
如果(名称5==“AA”){
常数x5=x[name5];
x[name5]=x5;//好的
}否则{
常数x5=x[name5];
x[name5]=x5;//好的
}

恐怕我没有一个很好的答案给你。TS3.5中改进的健壮性是100%正确的,并且确实捕获了bug,但也给开发人员带来了很多麻烦。通常我倾向于使用类型断言,因为它通常是实现目标的破坏性最小的更改

哦,好吧。希望有帮助!祝你好运

type Loosen<T extends object, K extends keyof T> = {
  [P in keyof T]: P extends K ? T[K] : T[P]
};

(x as Loosen<typeof x, typeof name2>)[name2] = x2; // okay
type L = Loosen<{ a: string; b: number; c: boolean }, "b" | "c">;
type L = {
    a: string;
    b: number | boolean;
    c: number | boolean;
}    
const name5 = Math.random() < 0.5 ? "AA" : "BB";
if (name5 === "AA") {
  const x5 = x[name5];
  x[name5] = x5; // okay
} else {
  const x5 = x[name5];
  x[name5] = x5; // okay
}