TypeScript 依赖的字符串文字属性和索引 [英] TypeScript dependent string literal properties and indexing
问题描述
类似于 Typescript: 依赖于同一对象中另一个属性的属性的类型我想要一个属性依赖的类型.
Similar to Typescript: Type of a property dependent on another property within the same object I want a type where the properties are dependent.
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
的类型为:
In the function, action.trait
is typed as:
(属性)特质:力量" |灵巧"|耐力" |魅力" |操纵" |外观" |感知" |情报" |机智"
(property) trait: "strength" | "dexterity" | "stamina" | "charisma" | "manipulation" | "appearance" | "perception" | "intelligence" | "wits"
所以它不能用于索引traits
.
我该如何解决这个问题?
How can I solve this?
推荐答案
我没有适合您的非冗余且类型安全的解决方案.您的 AttributeTrait
是我一直称之为 相关记录类型一>.这是一个有区别的联合,其中一些代码对于联合的每个成员都是安全的,但是编译器无法看到它对联合作为一个整体是安全的,因为它无法跟踪 相关之间的关联.code>category 和 trait
属性.
I don't have a non-redundant and type safe solution for you. Your AttributeTrait
is something I've been calling a correlated record type. It's a discriminated union where some bit of code is safe for each member of the union, but the compiler cannot see that it safe for the union as a whole, because it loses track of the correlation between the category
and trait
properties.
如果你编写冗余代码,错误就会消失:
If you write redundant code, the error goes away:
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 的原因,也是我提交 switch
/case
语句中写出,因此最好我能想到的是使用 类型断言 告诉编译器你比它更了解.
But try as you might, you can't collapse those cases into a single line of code and get the compiler to verify safety for you. That's why I filed microsoft/TypeScript#30581, and one reason I had filed microsoft/TypeScript#25051. Since you can't ask the compiler to treat the single line as if it had been written out in a switch
/case
statement, the best thing I can think of is to use a type assertion to tell the compiler that you know better than it does.
一种方法是撒一点谎,告诉编译器attributes
实际上在所有category
对象上都有所有trait
:
One way to do this is to lie a little bit and tell the compiler that attributes
actually has all trait
s on all category
objects:
function increment(action: AttributeTrait) {
(attributes as
Record<AttributeTrait["category"], {
traits: Record<AttributeTrait["trait"], number>
}>
)[action.category].traits[action.trait]++;
}
这比冗余代码的类型安全性差,但至少它可以让您继续前进.
This is less type safe than the redundant code, but at least it lets you move forward.
好的,希望有帮助;祝你好运!
Okay, hope that helps; good luck!
这篇关于TypeScript 依赖的字符串文字属性和索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!