TypeScript 依赖的字符串文字属性和索引 [英] TypeScript dependent string literal properties and indexing

查看:30
本文介绍了TypeScript 依赖的字符串文字属性和索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类似于 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 的原因,也是我提交 microsoft/TypeScript#25051.由于您不能要求编译器将单行 视为 已在 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 traits 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!

Playground 代码链接

这篇关于TypeScript 依赖的字符串文字属性和索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆