Typescript -类型“string”不能赋给字符串的联合类型

ozxc1zmp  于 2023-02-17  发布在  TypeScript
关注(0)|答案(1)|浏览(301)

我有一个组件,它获取一个union类型的prop:

export const RoleTag = ({ roleType }: { roleType: "BA" | "BM" | "BP" | "FR" | "RM" }) => {
    return (
        <Tag variant={ROLE_TAGS[roleType]} size="small" className="w-8 mr-2 rounded">
            {rolleType}
        </Tag>
    );
};

Tag组件也将变量定义为联合:

export interface TagProps extends HTMLAttributes<HTMLSpanElement> {
  children: React.ReactNode;
  /**
   * Changes visual profile of tag
   */
  variant:
    | "warning"
    | "warning-filled"
    | "error"
    | "error-filled"
    | "info"
    | "info-filled"
    | "success"
    | "success-filled"
    | "neutral"
    | "neutral-filled"
    | "alt1"
    | "alt1-filled"
    | "alt2"
    | "alt2-filled"
    | "alt3"
    | "alt3-filled";
  /**
   * @default "medium"
   */
  size?: "medium" | "small" | "xsmall";
}

我正在使用ROLE_TAG常量计算变量:

export enum RolleType {
    BM = "BM",
    BP = "BP",
    BA = "BA",
    RM = "RM",
    FR = "FR",
}

export const ROLE_TAGS = {
    [RolleType.BM]: "success",
    [RolleType.BP]: "alt1",
    [RolleType.BA]: "alt1",
    [RolleType.RM]: "alt3",
    [RolleType.FR]: "alt3",
};

但是,在当前设置下,我得到了一个Typescript错误:

TS2322: Type 'string' is not assignable to type '"success" | "alt1" | "alt3" | "warning" | "warning-filled" | "error" | "error-filled" | "info" | "info-filled" | "success-filled" | "neutral" | "neutral-filled" | "alt1-filled" | "alt2" | "alt2-filled" | "alt3-filled"'.

我做错了什么,我该怎么补救?

i5desfxk

i5desfxk1#

export const ROLE_TAGS = {
    [RolleType.BM]: "success",
    [RolleType.BP]: "alt1",
    [RolleType.BA]: "alt1",
    [RolleType.RM]: "alt3",
    [RolleType.FR]: "alt3",
};

因为它没有显式类型,所以typescript会推断出一个,当它看到字符串时,它会假设类型应该是string,所以推断出的类型是:

{
    BM: string;
    BP: string;
    BA: string;
    RM: string;
    FR: string;
}

由于属性的类型是string,因此有关特定值的信息丢失。因此,当您尝试在需要更特定值的地方使用string时,会出现错误。
如果你想让typescript的推理更加严格,你可以添加as const来告诉typescript这些值永远不会改变:

export const ROLE_TAGS = {
    [RolleType.BM]: "success",
    [RolleType.BP]: "alt1",
    [RolleType.BA]: "alt1",
    [RolleType.RM]: "alt3",
    [RolleType.FR]: "alt3",
} as const;

// Inferred type:
//{
//    readonly BM: "success";
//    readonly BP: "alt1";
//    readonly BA: "alt1";
//    readonly RM: "alt3";
//    readonly FR: "alt3";
//}

更高级的选项是对ROLE_TAGS使用新的satisfies运算符,如下所示:

export const ROLE_TAGS = {
    [RolleType.BM]: "success",
    [RolleType.BP]: "alt1",
    [RolleType.BA]: "alt1",
    [RolleType.RM]: "alt3",
    [RolleType.FR]: "alt3",
} satisfies { [key in RolleType]: TagProps['variant'] };

这告诉typescript它应该推断精确的值,但是它还应该验证结果类型是否与{ [key in RolleType]: TagProps['variant'] }匹配。因此,例如,如果您向RolleType添加一个新值,ROLE_TAGS将开始显示错误,因为它不再具有所需的所有属性。或者,如果有人编辑variant,使“success”不再是法律的值,在RolleType上您将再次得到一个错误。

相关问题