Last updated: Feb 27, 2024
Reading timeยท7 min
The "Type 'unknown' is not assignable to type" error occurs when we try to
assign a value with a type of unknown
to a value of a different type.
To solve the error, use a type assertion or a type guard to verify that the two values have compatible types before the assignment.
Here is an example of how the error occurs.
const a: unknown = 'Bobby Hadz'; // โ๏ธ Error: Type 'unknown' is not assignable to type 'string'.ts(2322) const b: string = a;
The a
variable has a type of
unknown.
The unknown
type is the type-safe counterpart of any
.
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
.
const a: unknown = 'Bobby Hadz'; const b: string = a as string;
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 the a
variable will be a string and not to
worry about it.
An alternative solution is to use a type guard.
const a: unknown = 'Bobby Hadz'; let b = ''; if (typeof a === 'string') { b = a; } console.log(b); // ๐๏ธ "Bobby Hadz"
We explicitly check if the variable a
stores a value of type string
before
making the assignment.
if
block, the variable a
is guaranteed to be a string.When working with the unknown
type, we basically tell TypeScript that we're
going to get this value, but we don't know its type.
We are going to check with a couple of if
statements to track the type down
and use it safely.
This way, TypeScript gives us support for the specified type in the if
block.
Here is an example of how you would use a type guard when working with objects.
const person: unknown = { name: 'Bobby Hadz', country: 'Chile', }; type Person = { name: string; country: string; }; // ๐๏ธ checks if obj has properties of Person function isPerson(obj: any): obj is Person { return ( typeof obj === 'object' && obj !== null && 'name' in obj && 'country' in obj ); } let bobby: Person; if (isPerson(person)) { // ๐๏ธ person has a type of Person here bobby = person; } else { bobby = { name: '', country: '' }; } console.log(bobby); // ๐๏ธ {name: 'Bobby Hadz', country: 'Chile'}
We used a
user-defined type guard
to check if an object has all of the properties of the Person
type.
obj is Person
syntax is a type predicate where obj
must be the name of the parameter the function takes.If the isPerson
function returns true
, TypeScript knows that the passed in
value is of type Person
and allows us to assign it to the variable.
The example simply checks if the passed-in value is an object and contains the
name
and country
properties.
We also had to check for null because in
JavaScript (and TypeScript), typeof null
returns "object"
.
If the person
variable doesn't store a value of a compatible type, we use
default values.
You could also set the default values upon initializing the variable.
const person: unknown = { name: 'Bobby Hadz', country: 'Chile', }; type Person = { name: string; country: string; }; // ๐๏ธ set defaults upon initialization let bobby: Person = { name: '', country: '', }; // ๐๏ธ checks if obj has properties of Person function isPerson(obj: any): obj is Person { return ( typeof obj === 'object' && obj !== null && 'name' in obj && 'country' in obj ); } if (isPerson(person)) { // ๐๏ธ person is type Person here bobby = person; } // ๐๏ธ {name: 'Bobby Hadz', country: 'Chile'} console.log(bobby);
Whether you are able to use this approach depends on your use case.
I've written a detailed guide on how to check if a value with an unknown type contains a property.
Here is an example of how to use a type guard to check if a value of type
unknown
is an array.
const data: unknown = [ { name: 'Bobby Hadz', country: 'Chile', }, { name: 'Alice', country: 'Germany', }, ]; type Person = { name: string; country: string; }; let people: Person[] = []; if (Array.isArray(data)) { people = data as Person[]; } // [ // { name: 'Bobby Hadz', country: 'Chile' }, // { name: 'Alice', country: 'Germany' } // ] console.log(people);
We used the Array.isArray()
method to check if the data
variable stores an
array before the assignment.
You might have to be more strict and check if the array has any elements and whether they contain specific properties.
I've also written an article on how to check if an array contains a value.
The error "Argument of type 'unknown' is not assignable to parameter of type"
occurs when we try to pass an argument of type unknown
to a function that
expects a different type.
To solve the error, use a type assertion or a type guard when calling the function.
Here is an example of how the error occurs.
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; // โ๏ธ Error: Argument of type 'unknown' is not assignable to parameter of type 'string'.ts(2345) getMessage(message);
The message
variable has a type of
unknown.
The unknown
type is the type-safe counterpart of any
.
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
when calling the function.
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; getMessage(message as string); // ๐๏ธ type assertion
Type assertions are used when we have information about the type of a value that TypeScript can't know about.
message
variable will be a string
and not to worry about it.any
typeIf you don't know the type of the function parameter and just want to turn off
type checking, use the any
type.
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; getMessage(message as any); // ๐๏ธ type assertion
The any
type effectively
turns off type checking, so we
wouldn't get a type error, but we also don't take advantage of TypeScript.
An alternative solution is to use a type guard.
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; if (typeof message === 'string') { const result = getMessage(message); console.log(result); // ๐๏ธ "Hello world" }
We explicitly check if the message
variable stores a value of type string
before calling the function.
if
block, the message
variable is guaranteed to be a string.When working with the unknown
type, we basically tell TypeScript that we're
going to get this value, but we don't know its type.
We are going to check with a couple of if statements to track the type down and use it safely.
In the if
blocks TypeScript gives us support for the type we are checking for.
Here is an example of how you would use a type guard when working with objects.
interface Employee { id: number; name: string; salary: number; } // ๐๏ธ Check if the passed-in object has the properties of Employee function isAnEmployee(obj: any): obj is Employee { return ( typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj && 'salary' in obj ); } const obj: unknown = { id: 1, name: 'Bobby Hadz', salary: 500, }; function getEmployee(emp: Employee) { return emp; } if (isAnEmployee(obj)) { // ๐๏ธ obj is type Employee here const result = getEmployee(obj); console.log(result); // ๐๏ธ {id: 1, name: 'Bobby Hadz', salary: 500} }
We used a
user-defined type guard
to check if an object has all of the properties of the Employee
type.
obj is Employee
syntax is a type predicate where obj
must be the name of the parameter the function takes.If the isAnEmployee
function returns true
, TypeScript knows that the passed
in value is of type Employee
and allows us to pass the object as an argument
to the function.
The example simply checks if the passed-in value is an object and contains the
id
, name
and salary
properties.
The goal is to make sure that the type of the argument we are passing to the function is compatible with the type of the function's parameter.
Here is an example of how to use a type guard to check if a value of type
unknown
is an array.
type Employee = { id: number; name: string; salary: number; }; const emps: unknown = [ { id: 1, name: 'Alice', salary: 100 }, { id: 2, name: 'Bobby Hadz', salary: 200 }, { id: 3, name: 'Carl', salary: 300 }, ]; function getEmployees(emps: Employee[]) { return emps; } if (Array.isArray(emps)) { getEmployees(emps as Employee[]); }
We used the Array.isArray()
method to check if the emps
variable stores an
array before the assignment.
You might have to be more strict and check if the array has any elements and whether they contain specific properties.
You can learn more about the related topics by checking out the following tutorials: