Home > Software engineering >  Any idea why Typescript behaves this way with Material UI Alert severity prop?
Any idea why Typescript behaves this way with Material UI Alert severity prop?

Time:10-01

I have a react project fired up with Typescript and am getting the following error

Type 'string' is not assignable to type 'Color | undefined'.

When I have something like this...

const foo = {stuff:"success"}

<MuiAlert
  onClose={handleSnackbarClose} 
  severity={foo.stuff}
>
  Words
</MuiAlert>

Yet the code works fine if the const foo is a string...

const foo = "success"

<MuiAlert
  onClose={handleSnackbarClose} 
  severity={foo}
>
  Words
</MuiAlert>

Is there a difference between invoking a variable that is a string and invoking a string that's inside of an object?

CodePudding user response:

The underlying types are handled differently in the examples you shared. In more detail:

const foo = "success"

The type of foo is now literally "success". Typescript knows that it was set to "success" and that, because it's a constant, it will never change.

However, this:

const foo = { stuff: "success"}

...is resolved to the type {stuff: string}. Typescript knows that it is an object with the key "stuff" on it, but because objects are mutable it doesn't know that bar.stuff will always be "success". It falls back to the more generic string type.

The error you're getting, then, is because the Color type that you've defined somewhere accepts the value "success", but it doesn't accept any string. So the first example is acceptable to the compiler, but it doesn't know that the second one should conform to the same set of values.

An alternative would be to do something like this:

const foo: {stuff: Color} = {stuff: "success"}

That way, Typescript will know that foo's stuff field will always be a Color. As a bonus, you get autocomplete when you start typing the string that you'll store in foo.stuff.

CodePudding user response:

This is because severity is typed as a so called Literal Type in MUI.
They defined the severity to only accept a Union of several strings.

The problem with your code is described in the Typescript handbook under Literal inference.

foo.stuff is of type string only and not a literal type of 'success', but if you assign foo to the value directly it can represent both the string type and the literal type 'success', which is what the severity prop accepts.

Or more generic: foo is constant, but foo.stuff is not. foo.stuff might change at any time and no longer contain the value you just assigned it. As you didn't type foo explicitly, any string value is acceptable for foo.stuff, not only the literal string you just assigned it to.

  • Related