Argument type 'X' not assignable to parameter of type 'Y'

avatar

Borislav Hadzhiev

Wed Mar 23 20225 min read

banner

Photo by Erik Mclean

Argument type 'X' not assignable to parameter of type 'Y' #

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.

argument type not assignable parameter type

Here is an example of how the error occurs.

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

To solve the error, we have to make sure the argument we are passing to the function has a compatible type with the function's parameter.

For example, you could widen the type of the function's parameter to be number or string.

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

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

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

This means that the property can store a string or an undefined value.

The name parameter is of type string, so it only expects to get assigned a string.

TypeScript is basically telling us that the 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.

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

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

This way we can be sure that the 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.

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

This helps us make sure that the type on the passed in argument and the type of the function's parameter are compatible.

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.

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

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

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

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

Use the search field on my Home Page to filter through my more than 1,000 articles.