Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Typescript – Type 'string' is not assignable to union type of strings

I have a component that gets a prop that is of a union type:

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 component has defined variant as union as well:

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";
}

I am computing variant by using ROLE_TAG constant:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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",
};

But, with the current setup I get a Typescript error:

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"'.

What am I doing wrong here, how can I fix this?

>Solution :

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

Since this doesn’t have an explicit type, typescript infers one. When it sees strings, it assumes the type should be string, so the inferred type is:

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

Since the type for the properties is string, the information about the specific values is lost. So when you try to use a string where a more specific value is required, you get an error.

If you want typescript to be stricter in its inference you can add as const to tell typescript that the values will never change:

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";
//}

A more advanced option is to use the new satisfies operator on ROLE_TAGS, as in:

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'] };

This tells typescript that it should infer the exact values, but it should also verify whether the resulting type matches with { [key in RolleType]: TagProps['variant'] }. So if, for example, you add a new value to RolleType, ROLE_TAGS will start to show an error because it no longer has all the properties it needs. Or if someone edits variant so that "success" is no longer a legal value, you’ll again get an error on RolleType.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading