gpt4 book ai didi

基于嵌套对象内部属性的 Typescript 联合

转载 作者:行者123 更新时间:2023-12-01 21:37:40 29 4
gpt4 key购买 nike

我正在尝试基于对象中的嵌套属性创建联合类型。请参见下面的示例:

type Foo = {
abilities: {
canManage: boolean
}
}

type Bar = {
abilities: {
canManage: boolean
}
extraProp: number
}

type Condition1 = {
abilities: {
canManage: true
}
} & Bar

type Condition2 = {
abilities: {
canManage: false
}
} & Foo

type TotalData = Condition1 | Condition2

const data: TotalData = {
abilities: {
canManage: false, // if canManage is false, TS should complain when I add the `extraProp` key
},
extraProp: 5
}

我遇到的问题是 typescript 忽略了我设置的条件。如果 canMange 值为 true,我只对允许某些属性感兴趣。这在嵌套时似乎不起作用。但是,如果我没有嵌套而只是像这样的东西,那就没问题了:

type Foo = {
canManage: boolean
}

type Bar = {
canManage: boolean
extraProp: number
}

type Condition1 = {
canManage: true
} & Bar

type Condition2 = {
canManage: false
} & Foo
]
type TotalData = Condition1 | Condition2

const data: TotalData = {

canManage: false,
extraProp: 5 // now typescript complains that this property shouldn't be here because canManage is false
}

尝试根据嵌套对象内的属性设置联合时,我该如何解决这个问题?

最佳答案

编译器不理解“嵌套可区分联合”的概念。如果并集的成员共享一个共同的“可判别”属性,则类型是可判别联合。判别属性通常是单例/文字类型,如 true"hello"123 甚至 null未定义。不过,您不能使用另一个被区分的联合作为判别式本身。如果可以的话,那就太好了,因为那时受歧视的联合可以按照您正在做的方式从嵌套属性向上传播。 microsoft/TypeScript#18758 有建议允许这样做,但我没有看到那里有任何动静。

就目前而言,TotalData 类型不是可区分 联合。这只是一个工会。这意味着编译器不会尝试将 TotalData 类型的值视为 独占 Condition1Condition2。因此,如果您编写测试 data.abilities.canManage 的代码并期望编译器理解其含义,您可能会遇到问题:

function hmm(x: TotalData) {
if (x.abilities.canManage) {
x.extraProp.toFixed(); // error!
// ~~~~~~~~~~~ <--- possibly undefined?!
}
}

如果您想这样做,您可能会发现自己需要编写 user-defined type guard functions相反:

function isCondition1(x: TotalData): x is Condition1 {
return x.abilities.canManage;
}

function hmm(x: TotalData) {
if (isCondition1(x)) {
x.extraProp.toFixed(); // okay!
}
}

您在这里遇到的具体问题,其中 data 被视为有效的 TotalDataexcess property checking 有何关系?被执行。 TypeScript 中的对象类型是“开放”/“可扩展”,而不是“封闭”/“exact”。在不违反类型的情况下,您可以添加类型定义中未提及的额外属性。所以编译器不能完全禁止多余的属性;相反,它使用启发式方法来尝试找出这些属性何时是错误的以及何时是故意的。主要使用的规则是:如果您正在创建一个全新的对象字面量,并且它的任何属性在使用它的类型中都没有提及,则会出现错误。否则不会有。

如果 TotalData 是一个有区别的联合,您会在 data 上得到预期的错误,因为 data.abilities.canManage 会导致编译器将 dataTotalData 缩小到 Condition2,其中没有提到 extraProp。但事实并非如此,因此 data 仍然是 TotalData确实提到了 extraProp

有人提议,在microsoft/TypeScript#20863 ,对非歧视工会的超额属性(property)检查更加严格。我非常同意;混合和匹配来自不同联合成员的属性似乎不是常见的用例,因此警告可能会有所帮助。但同样,这是一个长期存在的问题,我没有看到任何进展。


为此,您可以做的一件事是更明确地说明您要防止的过多属性。 {a: string} 类型的值可以具有 string 类型的 b 属性,但 {a: string, b?: never} 不能。因此,后一种类型将阻止 b 类型的属性,而无需依赖编译器的启发式方法来进行额外的属性检查。

在你的情况下:

type Foo = {
abilities: {
canManage: boolean
};
extraProp?: never
}

的行为与您原来的 Foo 定义非常相似,但现在您会收到此错误:

const data: TotalData = { // error!
// -> ~~~~
// Type '{ abilities: { canManage: false; }; extraProp: number; }'
// is not assignable to type 'TotalData'.
abilities: {
canManage: false,
},
extraProp: 5
}

编译器无法再使 dataCondition1Condition2 保持一致,因此它会报错。


好的,希望对你有帮助;祝你好运!

Playground link to code

关于基于嵌套对象内部属性的 Typescript 联合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61732108/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com