Type 'unknown' is not assignable to type in TypeScript

avatar
Borislav Hadzhiev

Last updated: Feb 27, 2024
7 min

banner

# Table of Contents

  1. Type 'unknown' is not assignable to type in TypeScript
  2. Argument type 'unknown' is not assignable parameter of type

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

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.

index.ts
const a: unknown = 'Bobby Hadz'; // โ›”๏ธ Error: Type 'unknown' is not assignable to type 'string'.ts(2322) const b: string = a;

type unknown is not assignable to type

The a variable has a type of unknown.

This often happens when fetching data from a remote API because TypeScript doesn't know the shape of the values we're working with.

The unknown type is the type-safe counterpart of any.

# Use a type assertion to solve the error

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.

index.ts
const a: unknown = 'Bobby Hadz'; const b: string = a as string;

use type assertion to solve the error

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 the a variable will be a string and not to worry about it.

Now that the values on the left and right-hand sides have compatible types, the assignment doesn't cause the error.

# Use a type guard to solve the error

An alternative solution is to use a type guard.

index.ts
const a: unknown = 'Bobby Hadz'; let b = ''; if (typeof a === 'string') { b = a; } console.log(b); // ๐Ÿ‘‰๏ธ "Bobby Hadz"

use type guard to solve the error

The code for this article is available on GitHub

We explicitly check if the variable a stores a value of type string before making the assignment.

TypeScript knows that once we're in the 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.

# Using a type guard to check for an object

Here is an example of how you would use a type guard when working with objects.

index.ts
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'}
The code for this article is available on GitHub

We used a user-defined type guard to check if an object has all of the properties of the Person type.

The 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.

index.ts
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.

The goal is to make sure that the values on the left-hand and right-hand sides of the assignment have compatible types.

I've written a detailed guide on how to check if a value with an unknown type contains a property.

# Using a type guard to check for an array

Here is an example of how to use a type guard to check if a value of type unknown is an array.

index.ts
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);

use type guard to check for an array

The code for this article is available on GitHub

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.

# Argument type 'unknown' is not assignable parameter of type

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.

argument type unknown not assignable parameter

Here is an example of how the error occurs.

index.ts
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.

This often happens when fetching data from a remote API because TypeScript doesn't know the shape of the values we're working with.

The unknown type is the type-safe counterpart of any.

# Using a type assertion to solve the error

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.

index.ts
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; getMessage(message as string); // ๐Ÿ‘ˆ๏ธ type assertion

using type assertion to solve the error

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 the message variable will be a string and not to worry about it.

# Turning off type checking with the any type

If you don't know the type of the function parameter and just want to turn off type checking, use the any type.

index.ts
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.

# Using a type guard to solve the error

An alternative solution is to use a type guard.

index.ts
function getMessage(message: string) { return message; } const message: unknown = 'Hello world'; if (typeof message === 'string') { const result = getMessage(message); console.log(result); // ๐Ÿ‘‰๏ธ "Hello world" }
The code for this article is available on GitHub

We explicitly check if the message variable stores a value of type string before calling the function.

TypeScript knows that once we're in the 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.

# Using a type guard when checking for objects

Here is an example of how you would use a type guard when working with objects.

index.ts
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} }
The code for this article is available on GitHub

We used a user-defined type guard to check if an object has all of the properties of the Employee type.

The 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.

# Using a type guard when checking for arrays

Here is an example of how to use a type guard to check if a value of type unknown is an array.

index.ts
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[]); }
The code for this article is available on GitHub

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.

# 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