Quantcast
Viewing latest article 43
Browse Latest Browse All 119

Answer by Simon_Weaver for TypeScript Type 'string' is not assignable to type

There are several situations that will give you this particular error. In the case of the OP, there was a value defined explicitly as a string. So I have to assume that maybe this came from a dropdown, or web service or raw JSON string.

In that case a simple cast <Fruit> fruitString or fruitString as Fruit is the only solution (see other answers). You wouldn't ever be able to improve on this at compile time. See my other answer about <const>!

However, it's very easy to run into this same error when using constants in your code that aren't ever intended to be of type string. My answer focuses on that second scenario:


First of all: Why are 'magic' string constants often better than an enum?

  • I like the way a string constant looks vs. an enum; it's compact and 'JavaScripty'
  • Makes more sense if the component you're using already uses string constants.
  • Having to import an 'enum type' just to get an enumeration value can be troublesome in itself
  • Whatever I do, I want it to be compile safe, so if I add remove a valid value from the union type, or mistype it then it must give a compile error.

Fortunately, when you define:

export type FieldErrorType = 'none' | 'missing' | 'invalid'

...you're actually defining a union of types where 'missing' is actually a type!

I often run into the 'not assignable' error if I have a string like 'banana' in my TypeScript code and the compiler thinks I meant it as a string, whereas I really wanted it to be of type banana. How smart the compiler is able to be will depend on the structure of your code.

Here's an example of when I got this error today:

// This gives me the error 'string is not assignable to type FieldErrorType'fieldErrors: [ { fieldName: 'number', error: 'invalid' } ]

As soon as I found out that 'invalid' or 'banana' could be either a type or a string, I realized I could just assert a string into that type. Essentially, cast it to itself, and tell the compiler no, I don't want this to be a string!

// So this doesn't gives any error, and I don't need to import the union type eitherfieldErrors: [ { fieldName: 'number', error: <'invalid'> 'invalid' } ]

So what's wrong with just 'casting' to FieldErrorType (or Fruit)?

// Why not do this?fieldErrors: [ { fieldName: 'number', error: <FieldErrorType> 'invalid' } ]

It's not compile time safe:

<FieldErrorType> 'invalidddd';  // COMPILER ALLOWS THIS - NOT GOOD!<FieldErrorType> 'dog';         // COMPILER ALLOWS THIS - NOT GOOD!'dog' as FieldErrorType;        // COMPILER ALLOWS THIS - NOT GOOD!

Why? This is TypeScript, so <FieldErrorType> is an assertion and you are telling the compiler a dog is a FieldErrorType! And the compiler will allow it!

But if you do the following, then the compiler will convert the string to a type

<'invalid'> 'invalid';     // THIS IS OK  - GOOD<'banana'> 'banana';       // THIS IS OK  - GOOD<'invalid'> 'invalidddd';  // ERROR       - GOOD<'dog'> 'dog';             // ERROR       - GOOD

Just watch out for stupid typos like this:

<'banana'> 'banan';    // PROBABLY WILL BECOME RUNTIME ERROR - YOUR OWN FAULT!

Another way to solve the problem is by casting the parent object:

My definitions were as follows:

   export type FieldName = 'number' | 'expirationDate' | 'cvv';   export type FieldError = 'none' | 'missing' | 'invalid';   export type FieldErrorType = { field: FieldName, error: FieldError };

Let's say we get an error with this (the string not assignable error):

  fieldErrors: [ { field: 'number', error: 'invalid' } ]

We can 'assert' the whole object as a FieldErrorType like this:

  fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]

Then we avoid having to do <'invalid'> 'invalid'.

But what about typos? Doesn't <FieldErrorType> just assert whatever is on the right to be of that type. Not in this case; fortunately the compiler will complain if you do this, because it's clever enough to know it's impossible:

  fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]

Viewing latest article 43
Browse Latest Browse All 119

Trending Articles