Last updated: Feb 27, 2024
Reading timeยท9 min
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.
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);
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.
string
type is too broad when one of the string literals draft
, read
or unread
is expected.To solve the error, use a
type assertion
to cast the string to be of type EmailStatus
.
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"
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.
Let's look at another example of how the error occurs.
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);
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.
type Letter = 'a' | 'b'; const arr: Letter[] = ['a', 'b']; const obj: { letter: string } = { letter: 'a', }; arr.push(obj.letter as Letter); // ๐๏ธ type assertion
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.
Let's look at another example of how the error occurs.
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[]
.
One way to solve the error is to use a const assertion.
type EmailStatus = 'draft' | 'read' | 'unread'; // ๐๏ธ type is readonly ["unread"] const arr2 = ['unread'] as const; const arr3: EmailStatus[] = ['draft', 'read']; const arr4: EmailStatus[] = [...arr2, ...arr3];
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.
A more universal approach is to use a type assertion as we did in the previous examples.
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.
Another common cause of the error is using enums with hardcoded strings.
export enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } // โ๏ธ Type '"READ"' is not assignable to type 'EmailStatus'.ts(2322) const status: EmailStatus = 'READ';
The best way to get around this is to access the specific property on the enum if possible.
export enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } // โ Solution 1 const status: EmailStatus = EmailStatus.Read; // โ Solution 2 const status2: EmailStatus = 'READ' as EmailStatus;
If, for some reason, you can't access the property on the enum, use a type assertion.
Trying to use hardcoded strings with enums is a common cause of the error.
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.
// ๐๏ธ 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.
For example, you could set the name
variable to have a type of
string | number
.
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
.
Here is another example of how the error occurs.
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.
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
.
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.
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
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.
An alternative and much better approach is to use a type guard.
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.
name
variable will always get assigned a string, even if person.name
is undefined
.if
statement to solve the errorIn more complex scenarios, you can use an if
statement as a type guard.
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"
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.
Here is another example of how the error occurs.
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.
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.
If you don't want to set the property to optional, you could default it to a compatible type.
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.
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
.
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.
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
.
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.
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.
You can learn more about the related topics by checking out the following tutorials: