Borislav Hadzhiev
Wed Mar 23 2022·5 min read
Photo by Erik Mclean
The error "Argument of type 'X' is not assignable ot parameter of type 'Y'" occurs when the passed in argument and the expected parameter types are incompatible. To solve the error, use a type assertion or a type guard to verify the argument is of a compatible type.
Here is an example of how the error occurs.
function doubleNumber(num: number) { return num * 2; } // ⛔️ Error: Argument of type 'string' is not assignable // to parameter of type 'number'.ts(2345) doubleNumber('hello');
The function takes a parameter of type number
, but we are passing it an
argument of type string
.
For example, you could widen the type of the function's parameter to be number
or string
.
function getNumberOrString(numOrStr: number | string) { return numOrStr; } getNumberOrString('hello');
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.
If you just want to turn off type checking when calling the function, you can
use a type assertion with the any
type.
function getString(str: string) { return str; } const str = 'Hello'; getString(str as unknown as any); // 👈️ type assertion
Here is another example of how the error occurs.
interface Employee { id: number; name?: string; // 👈️ optional (might be undefined) } function getEmployeeName(name: string) { return name; } const emp: Employee = { id: 1, name: 'Alice' }; // ⛔️ Argument of type 'string | undefined' is not assignable //to parameter of type 'string'. // Type 'undefined' is not assignable to type 'string'.ts(2345) getEmployeeName(emp.name);
The name
property is marked as
optional
in the Employee
interface.
string
or an undefined
value.The name
parameter is of type string
, so it only expects to get assigned a
string
.
emp.name
property might have a value of undefined
, which is not compatible with the type of the name
parameter, which only expects a string
.Here are a couple of examples of how you can solve the error.
interface Employee { id: number; name?: string; // 👈️ optional (might be undefined) } function getEmployeeName(name: string) { return name; } const emp: Employee = { id: 1, name: 'Alice' }; getEmployeeName(emp.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 emp.name
will be a string and not to worry
about it.
An alternative, and much better approach is to use a type guard.
interface Employee { id: number; name?: string; // 👈️ optional (might be undefined) } function getEmployeeName(name: string) { return name; } const emp: Employee = { id: 1, name: 'Alice' }; const empName: string = typeof emp.name === 'string' ? emp.name : ''; getEmployeeName(empName);
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 empName
variable, otherwise we use an empty string as a fallback.
empName
variable will always get assigned a string, even if emp.name
is undefined
.In more complex scenarios, you can use an if
statement as a type guard.
interface Employee { id: number; name?: string; // 👈️ optional (might be undefined) } function getEmployeeName(name: string) { return name; } const emp: Employee = { id: 1, name: 'Alice' }; if (typeof emp.name === 'string') { const result = getEmployeeName(emp.name); console.log(result); // 👉️ "Alice" }
In the if
statement, we check if the emp.name
property has a type of string
and if it does, we pass it as an argument to the getEmployeeName
function.
When working with objects, it's harder to make sure that the argument and the function's parameter are compatible types.
You can use a user-defined type guard to make sure that an object is of the expected type.
type Employee = { id: number; name: string; }; function getEmployee(emp: Employee) { return emp; } // 👇️ typed as unknown const obj: unknown = { id: 1, name: 'Tom', }; // 👇️ checks if passed in object is type Employee function isEmployee(obj: any): obj is Employee { return ( typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj ); } if (isEmployee(obj)) { // 👉️ obj has type Employee here const result = getEmployee(obj); console.log(result); // 👉️ {id: 1, name: 'Tom'} }
We used a user-defined type guard to check if an object contains specific properties before passing it as an argument to the function.
obj is Employee
syntax is a type predicate where obj
must be the name of the parameter the function takes.If the isEmployee
function returns true
, TypeScript knows that the passed in
value is of type Employee
and allows us to access all properties and methods
on the specific interface.
The example above simply checks if the passed in value is an object that
contains the id
and name
properties.
If you need to check if a specific value is an array before passing it as an
argument to a function, use the Array.isArray
method.
type Employee = { id: number; name: string; salary: number; }; const emps: unknown = [ { id: 1, name: 'Tom', salary: 100 }, { id: 2, name: 'Ben', salary: 200 }, { id: 3, name: 'Bob', 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, etc.
The cause of the "Argument of type 'X' is not assignable to parameter of type 'Y'" error is that the type of the function's parameter and the type of the passed in argument are not compatible.
So, depending on your use case, you could also solve the error by updating the type of the function's parameter and making the parameter and the passed in argument compatible types.
type Employee = { id: number; name: string; }; type Developer = { name: string; language: string; }; // 👇️ parameter type is Employee or Developer function getEmployee(emp: Employee | Developer) { return emp; } // 👇️ argument type is also Employee | Developer const person: Employee | Developer = Math.random() > 0.5 ? { id: 1, name: 'Bob' } : { name: 'Alice', language: 'TypeScript' }; getEmployee(person);
The function's parameter is of type Employee
or Developer
and the passed in
argument is also of type Employee
or Developer
. We don't get a type checking
error because the two types are compatible.