假设我有以下类型:
type A = {
role: 'admin',
force?: boolean
}
type B = {
role: 'regular',
}
type Or = A | B;
我希望能够做到:
const or = {
role: 'regular'
} as Or;
const {role, force} = or;
而不会出现错误:
Property 'force' does not exist on type 'Or'.(2339)
和不使用触摸A
和B
我试着去做:
type Merge<Obj> = {
[k in keyof Obj]: Obj[k]
}
const {role, force} = or as Merge<Or>;
但同样的错误
打字机游戏场
4条答案
按热度按时间slhcrj9b1#
TypeScript对象类型不是 sealed 或 exact(如microsoft/TypeScript#12936中所要求的)。仅仅因为一个类型没有提到一个属性,它并没有 * 禁止 * 该属性。所以从技术上讲,类型
{role: "regular"}
的值可能有一个名为force
的属性,该属性的类型完全未知:按照这种逻辑,你要做的事情是不安全的,唯一一个将
Or
类型的值分解成碎片的 * 安全 * 方法是使force
属性成为unknown
类型。但是从现在开始,让我们假设这个问题不会出现,并且我们Assert该值只具有编译器已知的属性,并且该类型中没有提到的任何属性都将是
undefined
类型。那么,我们如何“修复”像
Or
这样的联合类型,使其成为一个显式知道其他成员的所有键的版本,以便编译器允许您使用这些键中的任何键对它进行索引?这里有一个可能的方法:
首先让我们确认它在
Or
上是否工作:这看起来是正确的。两个联合体成员都有一个
role
和一个force
属性。第一个成员与A
相同,而第二个成员是B
,它带有一个undefined
类型的可选属性。因此,现在您可以对它进行反结构:那么它是如何工作的呢?首先让我们看看
K
类型参数。我实际上只是使用一个默认值来计算T
联合体中每个成员的所有键。类型T extends unknown ? keyof T : never
是一个分布式条件类型,它将T
分解为它的联合体成员,获取它们各自的键,然后将它们重新组合成一个新的并集,我有时将此操作称为AllKeys<T>
,如Is it possible to get the keys from a union of objects?所示,对于Or
,K
将为"role" | "force"
。所以现在
K
是所有的键,FixUnion<T>
的主体是另一个分布式条件类型;对于T
联合体的每个成员,我们将其与{ [P in Exclude<K, keyof T>]?: never }
求交集,这是一个具有所有可选键的mapped type(因此是?
),它们存在于K
中,但不在当前联合成员中(使用Exclude<T, U>
实用程序类型)。并且属性值是never
,不可能的类型。对于Or
,第一个成员将看起来像A & {}
,第二个成员将看起来像B & { force?: never }
。注意,可选属性自动在其域中获得undefined
,所以它和B & { force?: undefined }
是一样的,关键是第二个联合成员中的force
属性不是丢失就是undefined
。最后,为了使事物更美观,我使用了一种技术,将像
A & {}
这样的交叉点变成像{role: "admin", force?: boolean}
这样的普通对象,如How can I see the full expanded contract of a Typescript type?中所述;... extends infer O ? {[P in keyof O]: O[P]} : never}
就是这么做的,所以第一个成员变成了{role: "admin", force?: boolean}
,第二个变成了{role: "regular", force?: undefined}
。让我们在另一个联合体上测试一下,看看它是如何工作的:
所有四个联合成员都具有所有三个键,但至少有两个键是
undefined
类型的可选键。Playground代码链接
eoigrqb62#
不能访问只有联合类型的某些成员才具有的联合类型的属性。
你会得到同样的错误,同样的原因是这个简化的代码:
如果你想要那个属性,那么你必须首先证明它存在,这就把你的并集缩小到了那个属性的值。
见Playground
你可以把同样的东西添加到你的操场上,以使类型检查通过。
见Playground
另外值得一提的是,这种类型:
没有什么用,它把一个对象类型的键Map到这些键的值类型,它和输入类型完全一样,所以不管你认为它应该做什么,它没有做。
kxxlusnw3#
使用
Pick
实用程序来实现这一点,下面是我的解决方案,您可能会认为有帮助:hmae6n7t4#
乡巴佬黑客:
const {role, force} = or as any;
但说真的,你不能。 typescript 正在帮助你解决这个问题。如果你这样做了,它会起作用:
这样,编译器将它与类型A匹配,类型A至少有机会具有
force
,因此这里的force是类型boolean | undefined