TypeScript compiler errors can be big and scary, and a good skill to have in your back pocket when errors do happen is being able to interpret the key information in the error to help you understand the problem and iterate over solutions. Let's take a look at two errors that might be hard to understand and catch you off guard.
No overload matches this call
No overload matches this call.
Overload 1 of 2, '(options: B): Promise<void>', gave the following error.
Argument of type 'A | B' is not assignable to parameter of type 'B'.
Type 'A' is not assignable to type 'B'.
Type 'A' is not assignable to type '{ async: true; }'.
Types of property 'async' are incompatible.
Type 'false | undefined' is not assignable to type 'true'.
Type 'undefined' is not assignable to type 'true'.
Overload 2 of 2, '(options: A): void', gave the following error.
Argument of type 'A | B' is not assignable to parameter of type 'A'.
Type 'B' is not assignable to type 'A'.
Types of property 'async' are incompatible.
Type 'true' is not assignable to type 'false | undefined'.
Whew boy, that's a big one. There's a lot of information here, so let's unpack this. First step when reading any error is filtering out unneeded information, and looking at keywords to extract from the message: "No overload matches this call". Under the error message, there's two overloads that are reporting errors:
Overload x of y, '(arguments): return type', gave the following error.
With each line of indentation, the error goes more and more into detail about what caused the error for each overload.
What exactly is an overload, and why does it matter that "no overloads match this call"?
An overload is essentially an alternative set of arguments and return type that a function can have depending on what is passed in. Let's take a simple add
function:
function add(a: number, b: number): number {
return a + b;
}
Let's say we wanted to add an "assertion mode" to this add
function, which will return true
or false
depending on if a third number we pass in (c
) equals the result of a + b
function add(a: number, b: number): number;
function add(a: number, b: number, c: number): boolean;
function add(a: number, b: number, c?: number) {
if (c) return a + b === c
return a + b
}
The add
function now has two overloads. It can be confusing, but the first two lines are function signatures and the last is the actual implementation for the function. The top definition has priority, and the line under that is the overload: a
, b
and c
must all be numbers and add
must return a boolean.
The compiler will match a specific overload, provided the call to the function is provided with arguments where the types match at least one of the overloads above.
If add
is called with two arguments, the first overload is matched:
If add
is called with three arguments, the second overload is matched:
In Visual Studio Code, you can see the overloads a function has on the left of the tooltip. Overloads aren't widely used in TypeScript anymore, many preferring to use unions.
Since we have an error complaining about "no overloads matching this call", we know it's related to arguments being passed into a function with multiple overloads, potentially with the wrong type. If you're seeing this error, it's best to double check that you're passing the right arguments with the right types into the function for the overload you want to target.
Types of property type
are incompatible
Argument of type '{ type: string };' is not assignable to parameter of type 'Schema'
Type '{ type: string; }' is not assignable to type 'Schema'
Types of property 'type' are incompatible.
Type 'string' is not assignable to type '"string" | "number"'
Usually when you see this error, you'll also see "type x
is not assignable to type y
". What does it mean for a type to be "not assignable" to another type?
TypeScript's own documentation explains what "assignable to" means, and says a type is considered assignable to another type if "one is an acceptable substitute for another" - basically, both types need to have the same "shape" or structure. You can't assign a number
to a string
, and you can't assign { a: number }
to { a: string }
. In both examples, you couldn't substitute the first type for the second or vice versa.
You might encounter this error if an object you're supplying to an argument for a function does not make a suitable substitute for the type the function is requesting for that argument (like the two objects in the example before). Double check that every property in the object you're supplying matches the type definition for the function you're using.
String literals vs string
type
One thing to be wary of if you get this error is the fact that the type string
is not assignable to one particular string literal, such as "test"
. In this cases, you might find yourself with an error like, Type 'string' is not assignable to type '"test"'
.
const getType = () => "string";
const type = getType();
type TestType = { type: "string" | "number" };
// Type 'string' is not assignable to type '"string" | "number"'
const obj: TestType = { type }; // ❌ type: string
A "string literal"
is a different type to string
(note the quote marks!) and it makes sense that the literal string "test"
is not a substitute for all strings (string
). However, any string literal like "test"
is assignable to string
.
A quick fix for this problem (for TypeScript 3.4+) is to add as const
to the end of your string so that the content of the string is the type.
const getType = () => "string" as const;
const type = getType();
type TestType = { type: "string" | "number" };
const obj: TestType = { type }; // ✅ type: 'string'
Something also worth mentioning is the difference between defining strings using var
or let
compared to const
. When defining a string using var
or let
, the compiler will infer the type as string
automatically. When defining a string using const
, the type will be the literal contents of the string.
let changingString = "Hello World";
// type is `string`: since variables defined with
// `let` are mutable, this *could* represent other
// values
const constantString = "Hello World";
// type is `"Hello World"`: this is a constant
// variable and can only represent one value
// using a method to change the string
// like `.reverse()` will simply change
// the type to a `string`
Conclusion
The TypeScript documentation has a good guide to understanding errors better, and there's a lot more you can do if the error you're facing is really stubborn. Try to strip unnecessary parts of code to get to the heart of the problem, or if all else fails, look into creating a minimal reproducible example (there's a good guide by StackOverflow) to see if you can reproduce the problem from scratch, and divide and conquer to find out if there's something wrong with your code, or potentially a dependency you use.
If you enjoyed this post, I'd love to hear any feedback! Write a comment, leave a reaction (❤️, 🦄) and share around with your TypeScript friends who are pulling their hair out!
Top comments (0)