类似于Typescript: Type of a property dependent on another property within the same object我想要一种属性依赖的类型。
const attributes = {
physical: {
traits: {
strength: 1,
dexterity: 1,
stamina: 1,
}
},
social: {
traits: {
charisma: 1,
manipulation: 1,
appearance: 1,
}
},
mental: {
traits: {
perception: 1,
intelligence: 1,
wits: 1,
}
}
};
type AttributeTrait =
| {
category: 'physical';
trait: keyof typeof attributes.physical.traits;
}
| {
category: 'social';
trait: keyof typeof attributes.social.traits;
}
| {
category: 'mental';
trait: keyof typeof attributes.mental.traits;
};
const action: AttributeTrait = {
category: 'social',
trait: 'manipulation'
}
function increment(action: AttributeTrait) {
attributes[action.category].traits[action.trait]++; // error 7053
}
在函数中,action.trait
的类型为:
(property) trait: "strength" | "dexterity" | "stamina" | "charisma" | "manipulation" | "appearance" | "perception" | "intelligence" | "wits"
因此它不能用于索引traits
。
我该如何解决这个问题?
最佳答案
我没有适合您的非冗余且类型安全的解决方案。你的 AttributeTrait
是我一直称之为 correlated record type 的东西.这是一个有区别的联合体,其中一些代码对于联合体的每个成员都是安全的,但是编译器看不到它对于整个联合体是安全的,因为它忘记了 相关性 category
和 trait
属性。
如果您编写冗余代码,错误就会消失:
function incrementRedundant(action: AttributeTrait) {
switch (action.category) {
case "physical":
attributes[action.category].traits[action.trait]++;
return;
case "social":
attributes[action.category].traits[action.trait]++;
return;
case "mental":
attributes[action.category].traits[action.trait]++;
return;
}
}
但是尽您所能,您不能将这些案例折叠成一行代码并让编译器为您验证安全性。这就是我提交 microsoft/TypeScript#30581 的原因,以及我提交 microsoft/TypeScript#25051 的原因之一.由于您不能要求编译器将单行 视为好像 它是在 switch
/case
语句中写出的,最好的我能想到的是使用 type assertion告诉编译器你比它更了解。
一种方法是撒一点谎,告诉编译器 attributes
实际上拥有所有 category
对象的所有 trait
:
function increment(action: AttributeTrait) {
(attributes as
Record<AttributeTrait["category"], {
traits: Record<AttributeTrait["trait"], number>
}>
)[action.category].traits[action.trait]++;
}
这比冗余代码的类型安全性差,但至少它可以让您继续前进。
好的,希望对你有帮助;祝你好运!
关于依赖于 TypeScript 的字符串文字属性和索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65369273/