Type 'string' is not assignable to type in TypeScript

avatar
Borislav Hadzhiev

Last updated: Feb 27, 2024
9 min

banner

# Table of Contents

  1. Type 'string' is not assignable to type in TypeScript
  2. Type String is not assignable to type Enum in TypeScript
  3. Type 'X' is not assignable to type 'Y' in TypeScript

# Type 'string' is not assignable to type in TypeScript

The "Type 'string' is not assignable to type" TypeScript error occurs when we try to assign a value of type string to something that expects a different type, e.g. a more specific string literal type or an enum.

To solve the error, use a const or a type assertion.

Here is the first example of how the error occurs.

index.ts
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐Ÿ‘‡๏ธ status has type `string` let status = 'draft'; status = 'read'; // โ›”๏ธ Error: Type 'string' is not // assignable to type 'EmailStatus'.ts(2322) const current: EmailStatus = status; console.log(current);

type string is not assignable to type

The status variable has a type of string and the current variable has a type of EmailStatus.

When we try to assign a string to a variable that expects a value of type EmailStatus, the error occurs.

TypeScript is telling us that the string type is too broad when one of the string literals draft, read or unread is expected.

# Use a type assertion to solve the error

To solve the error, use a type assertion to cast the string to be of type EmailStatus.

index.ts
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐Ÿ‘‡๏ธ type is EmailStatus (not string) let status = 'draft' as EmailStatus; // ๐Ÿ‘ˆ๏ธ use type assertion status = 'read'; const current: EmailStatus = status; console.log(current); // ๐Ÿ‘‰๏ธ "read"

use type assertion to solve the error

The code for this article is available on GitHub

We used a type assertion to change the type of the status variable to EmailStatus which resolved the error.

The error occurs because the string type has many more potential values than the EmailStatus type which only covers 3 string literal values.

# Calling a function with a value of an incorrect type

Let's look at another example of how the error occurs.

index.ts
type Letter = 'a' | 'b'; const arr: Letter[] = ['a', 'b']; const obj: { letter: string } = { letter: 'a', }; // โ›”๏ธ Argument of type 'string' is not // assignable to parameter of type 'Letter'.ts(2345) arr.push(obj.letter);

calling function with value of incorrect type

The letter property in the object is typed as string and the array only expects strings of type Letter.

To solve the error, change the type of the letter property in the object to Letter or use a type assertion.

index.ts
type Letter = 'a' | 'b'; const arr: Letter[] = ['a', 'b']; const obj: { letter: string } = { letter: 'a', }; arr.push(obj.letter as Letter); // ๐Ÿ‘ˆ๏ธ type assertion

using type assertion to solve the error

The code for this article is available on GitHub

We used a type assertion to get around the error. However, it would be better if we could directly type the letter property in the object as Letter.

I've also written a detailed guide on how to only allow specific string values with a TypeScript type.

# Using broader types than necessary

Let's look at another example of how the error occurs.

index.ts
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐Ÿ‘‡๏ธ type is string[] const arr2 = ['unread']; const arr3: EmailStatus[] = ['draft', 'read']; // โ›”๏ธ Error: Type 'string[]' is not // assignable to type 'EmailStatus[]'. const arr4: EmailStatus[] = [...arr2, ...arr3];

The arr2 variable has a type of string[] whereas arr4 has a much more specific type of EmailStatus[].

# Use a const assertion to solve the error

One way to solve the error is to use a const assertion.

index.ts
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐Ÿ‘‡๏ธ type is readonly ["unread"] const arr2 = ['unread'] as const; const arr3: EmailStatus[] = ['draft', 'read']; const arr4: EmailStatus[] = [...arr2, ...arr3];

using const assertion to solve the error

The code for this article is available on GitHub

The as const syntax converts the array to a read-only tuple that contains a single string - unread. This might not be what you want if you have to change the contents of the array.

# Use a type assertion to solve the error

A more universal approach is to use a type assertion as we did in the previous examples.

index.ts
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐Ÿ‘‡๏ธ type is EmailStatus[] const arr2 = ['unread'] as EmailStatus[]; const arr3: EmailStatus[] = ['draft', 'read']; const arr4: EmailStatus[] = [...arr2, ...arr3];

Now the arr2 variable is typed as EmailStatus[] so we can unpack it into arr4.

If you get the error Type 'string or null' is not assignable to type string, click on the link and follow the instructions.

# Type String is not assignable to type Enum in TypeScript

Another common cause of the error is using enums with hardcoded strings.

index.ts
export enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } // โ›”๏ธ Type '"READ"' is not assignable to type 'EmailStatus'.ts(2322) const status: EmailStatus = 'READ';

# Access the property on the Enum to solve the error

The best way to get around this is to access the specific property on the enum if possible.

index.ts
export enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } // โœ… Solution 1 const status: EmailStatus = EmailStatus.Read; // โœ… Solution 2 const status2: EmailStatus = 'READ' as EmailStatus;
The code for this article is available on GitHub

If, for some reason, you can't access the property on the enum, use a type assertion.

Enums are real objects that exist in runtime. The correct way to use them is to access their properties via dot or bracket notation.

Trying to use hardcoded strings with enums is a common cause of the error.

# Type 'X' is not assignable to type 'Y' in TypeScript

The "Type 'X' is not assignable to type 'Y'" TypeScript error occurs when the values on the left and right-hand side of the assignment have incompatible types.

To solve the error, use a type assertion or a type guard to verify the two values have compatible types before the assignment.

Here is an example of how the error occurs.

index.ts
// ๐Ÿ‘‡๏ธ let name: string let name = 'Bobby Hadz'; // โ›”๏ธ Type 'number' is not assignable to type 'string'.ts(2322) name = 100;

We initialized the name variable and set it to a string. The variable has a type of string so trying to assign a value of a different type causes an error.

To solve the error, make sure the two values have compatible types or use a type assertion.

# Using a union type to solve the error

For example, you could set the name variable to have a type of string | number.

index.ts
let name: string | number = 'Bobby Hadz'; // โœ… Works now name = 100;

If you are certain that the specific value has a compatible type, but TypeScript doesn't know about it, use a type assertion, e.g. value as RightType.

# Another example of how the error occurs

Here is another example of how the error occurs.

index.ts
interface Person { name?: string; // ๐Ÿ‘ˆ๏ธ optional (might be undefined) country: string; } const person: Person = { name: 'Bobby Hadz', country: 'Chile', }; // โ›”๏ธ Error const name: string = person.name;

The name property is marked as optional in the Person interface.

This means that the property can store a string or an undefined value.

The name variable is typed as a string, so it only expects to get assigned a value that is a string.

TypeScript is basically telling us that the person.name property might have a value of undefined, which is not compatible with the type of the name variable, which only expects a string.

# Using a type assertion to solve the error

Here are a couple of examples of how you can solve the error.

index.ts
interface Person { name?: string; // ๐Ÿ‘ˆ๏ธ optional (might be undefined) country: string; } const person: Person = { name: 'Bobby Hadz', country: 'Chile', }; const name: string = person.name as string; // ๐Ÿ‘ˆ๏ธ type assertion
The code for this article is available on GitHub

Type assertions are used when we have information about the type of a value that TypeScript can't know about.

We effectively tell TypeScript that person.name will be a string and not to worry about it.

I've written a detailed guide on how to make an optional property required in TypeScript.

# Using a type guard to solve the error

An alternative and much better approach is to use a type guard.

index.ts
interface Person { name?: string; // ๐Ÿ‘ˆ๏ธ optional (might be undefined) country: string; } const person: Person = { name: 'Bobby Hadz', country: 'Chile', }; const name: string = typeof person.name === 'string' ? person.name : '';

We used the ternary operator to check if the name property has a type of string.

If the property has a type of string, it gets assigned to the name variable, otherwise, we use an empty string as a fallback.

This way we can be sure that the name variable will always get assigned a string, even if person.name is undefined.

# Using an if statement to solve the error

In more complex scenarios, you can use an if statement as a type guard.

index.ts
interface Person { name?: string; // ๐Ÿ‘ˆ๏ธ optional (might be undefined) country: string; } const person: Person = { name: 'Bobby Hadz', country: 'Chile', }; let name = ''; if (typeof person.name === 'string') { name = person.name; } console.log(name); // ๐Ÿ‘‰๏ธ "Bobby Hadz"
The code for this article is available on GitHub

We used the let keyword to initialize the name variable to an empty string.

In the if statement, we check if the person.name property has a type of string and assign the name variable to the corresponding value.

This helps us make sure that the types on the left and right-hand sides of the assignment are compatible.

# Another example of how the error occurs

Here is another example of how the error occurs.

index.ts
interface Person { name: string; country: string; } const people: Person[] = []; // โ›”๏ธ Error people[0] = { name: 'Bobby Hadz', country: undefined };

We tried to set the country property to an initial value of undefined but the Person type expects a value of type string.

The types of the two values are incompatible, so the type checker throws the error.

To solve the error, set the country property in the Person type to optional.

index.ts
interface Person { name: string; country?: string; // ๐Ÿ‘ˆ๏ธ optional } const people: Person[] = []; people[0] = { name: 'Bobby Hadz', country: undefined };

Now you could even omit the country property when doing the assignment. The types are compatible because the country property expects a value of type string or undefined.

You can use the Partial utility type if you need to mark all properties as optional.

# Picking a default value of a compatible type

If you don't want to set the property to optional, you could default it to a compatible type.

index.ts
interface Person { name: string; country: string; } const people: Person[] = []; people[0] = { name: 'Bobby Hadz', country: '' };

An empty string is a good default value in this case. What default value you use and whether you can use one depends on your use case.

Here is another common cause of the error.

index.ts
const arr = [1, 2, 3]; // ๐Ÿ‘‡๏ธ const result: number | undefined const result = arr.pop(); // โ›”๏ธ Error const first: number = result;

The Array.pop() method might return undefined if called on an empty array.

So when we try to assign the result of calling it to a variable that expects a number, we get the error because undefined is not assignable to type number.

# Using a type assertion to solve the error

There are many ways to get around this. For example, if you're sure that the value is a number, you could use a type assertion.

index.ts
const arr = [1, 2, 3]; // ๐Ÿ‘‡๏ธ const result: number | undefined const result = arr.pop(); const first: number = result as number;

We effectively tell TypeScript that result will be a number and not to worry about it.

# Using a union type to solve the error

Alternatively, you could type the first variable to have a type of number | undefined.

index.ts
const arr = [1, 2, 3]; // ๐Ÿ‘‡๏ธ const result: number | undefined const result = arr.pop(); const first: number | undefined = result;

Now the two sides of the assignment have compatible types, so the type checker doesn't error out.

# Using a suitable default value to solve the error

A third way to solve the error is to provide a default value in case the result variable doesn't store a number.

index.ts
const arr = [1, 2, 3]; // ๐Ÿ‘‡๏ธ const result: number | undefined const result = arr.pop(); const first: number = typeof result === 'number' ? result : 0;

In case the type of the result variable is not a number, we provide a default value of 0.

Whether this is a possible solution depends on your use case.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev