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

avatar

Borislav Hadzhiev

Last updated: Mar 7, 2022

banner

Photo from Unsplash

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 a very simple example of how the error occurs.

index.ts
// 👇️ let name: string let name = 'James'; // ⛔️ 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, we have to make sure the two values have compatible types or use a type assertion.

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

index.ts
let name: string | number = 'James'; // ✅ 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.

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: 'James', country: 'Chile', }; // ⛔️ Type 'undefined' is not assignable to type 'string'. 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.

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: 'James', country: 'Chile', }; const name: string = person.name as string; // 👈️ type assertion

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.

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: 'James', country: 'Chile', }; const name: string = typeof person.name === 'string' ? person.name : '';

We used a 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.

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: 'James', country: 'Chile', }; let name = ''; if (typeof person.name === 'string') { name = person.name; } console.log(name); // 👉️ "James"

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.

Here is another example of how the error occurs.

index.ts
interface Person { name: string; country: string; } const people: Person[] = []; // ⛔️ Type 'undefined' is not // assignable to type 'string'.ts(2322) people[0] = { name: 'James', 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.

A way to solve this is to 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: 'James', 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.

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: 'James', 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(); // ⛔️ Type 'undefined' is not // assignable to type 'number'. 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.

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.

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.

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.

Conclusion #

To solve the "Type 'X' is not assignable to type 'Y'" TypeScript error, make sure that the types of the values on the left and right-hand side of the assignment are compatible. If there is a mismatch between the types of the two values, the error is thrown.

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.