解构/访问对象联合类型上可能存在也可能不存在的属性



我得到以下错误:

type Union = { type: "1"; foo: string } | { type: "2"; bar: number };
function doSomething = (object: Union) => {
const { foo } = object
//      ^ TS2339: Property 'foo' does not exist on type 'Union'.
console.log(object.bar)
//                 ^ TS2339: Property 'bar' does not exist on type 'Union'.
}

期望结果:

typeof foo === string | undefined
typeof bar === number | undefined

如何在没有显式类型保护的情况下访问属性,例如:

const foo = o.type === 1 ? o.foo : undefined
const bar = o.type === 2 ? o.bar : undefined

这对我来说不是一个真正的选择,因为我正在处理大型联合,其中目标属性可能存在也可能不存在于许多对象中,这将是一个完全混乱的

我还有其他选择吗?

在对象类型的联合中访问属性失败,因为没有在所有联合成员上定义属性#12815

这里的问题是,因为B没有声明a属性,它可能在运行时具有任何可能类型的a属性(因为您可以将具有任何属性集的对象分配给B,只要它具有类型为string的B属性)。你可以让它显式地在B中声明a: undefined属性(从而确保B不会有一些随机的a属性):

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;
declare const AorB: AorB;
if (AorB.a) {
// Ok
}

您可以为未使用的属性设置never,然后TS可以将这些属性的类型理解为可选的。

type Type1 = { type: "1"; foo: string, bar?: never }
type Type2 = { type: "2"; foo?: never, bar: number }    
type Union = Type1 | Type2
const doSomething = (object: Union) => {
const { type, foo, bar } = object
console.log(type, foo, bar)
}
doSomething({ type: "1", foo: "foo" }) // [LOG]: "1",  "foo",  undefined 
doSomething({ type: "2", bar: 2 }) // [LOG]: "2",  undefined,  2 

TS游乐场链接:https://www.typescriptlang.org/play?代码/C4TwDgpgBAKuEEYoF4oG8qkgLigIgTwG4oAzAe3NwGdgAnASwDsBzAGigCMBDOgflxMIANwh0oAXwCwAKCzQ4kAEwp0meLjxLiZSgKhDRdDjzqCArgFtOYyVHtRZ8qAFUmDck1WLEUAD6w8EqysgDGnrRQACbkAMrklhDAABbMLKoAFOScAFYQocC4bh5MAJQoAHzosg5Q4UyRGPIcFOQmvHao2XkFNQ711OQANhAAdEPkLBnNum1cvKWy0jKyMfGJKWkZTRr4hC2Umq14kosyawlJqazb6jj42u1mUCoSZ0A

这种行为是有意义的,因为TS不知道它正在处理的是来自Union的哪个对象,并且在某些情况下该属性不存在。

我不确定这是否是你想要的,但你可以尝试像

这样的东西
type Union = { type: "1"; foo: string } | { type: "2"; bar: number };
function doSomething = (object: Union) => {
if ('foo' in object) {
const { foo } = object
}
if ('bar' in object) {
console.log(object.bar)
}
}

这是一个操场

我发现最方便的方法是根据变量的类型强制转换。

type Type1 = { type: "1"; foo: string }
type Type2 = { type: "2"; bar: number }    
type Union = Type1 | Type2
function doSomething = (object: Union) => {
const { foo } = object as Type1
const { bar } = object as Type2
const { type } = object  
}

最新更新