Published on 14/09/2021 by

Nevulo profile picture
Nevulo

How to read & troubleshoot TypeScript errors

Understand some common errors and what they mean instead of pulling your hair out

How to read & troubleshoot TypeScript errors

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

1No overload matches this call.
2 Overload 1 of 2, '(options: B): Promise<void>', gave the following error.
3 Argument of type 'A | B' is not assignable to parameter of type 'B'.
4 Type 'A' is not assignable to type 'B'.
5 Type 'A' is not assignable to type '{ async: true; }'.
6 Types of property 'async' are incompatible.
7 Type 'false | undefined' is not assignable to type 'true'.
8 Type 'undefined' is not assignable to type 'true'.
9 Overload 2 of 2, '(options: A): void', gave the following error.
10 Argument of type 'A | B' is not assignable to parameter of type 'A'.
11 Type 'B' is not assignable to type 'A'.
12 Types of property 'async' are incompatible.
13 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:

1Overload 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:

1function add(a: number, b: number): number {
2 return a + b;
3}

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

1function add(a: number, b: number): number;
2function add(a: number, b: number, c: number): boolean;
3function add(a: number, b: number, c?: number) {
4 if (c) return a + b === c
5 return a + b
6}

add function now has two overloads: screenshot shows top function signature with +1 overload

The add function now has two overloads. It can be confusing, but the first two lines are

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:

add function called with two arguments, first overload matched

If add is called with three arguments, the second overload is matched:

add function called with three arguments, second overload 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

.

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

1Argument of type '{ type: string };' is not assignable to parameter of type 'Schema'
2
3Type '{ type: string; }' is not assignable to type 'Schema'
4
5Types of property 'type' are incompatible.
6
7Type '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

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"'.

1const getType = () => "string";
2const type = getType();
3
4type TestType = { type: "string" | "number" };
5// Type 'string' is not assignable to type '"string" | "number"'
6const 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.

1const getType = () => "string" as const;
2const type = getType();
3
4type TestType = { type: "string" | "number" };
5const 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,

.

1let changingString = "Hello World";
2// type is `string`: since variables defined with
3// `let` are mutable, this *could* represent other
4// values
5
6const constantString = "Hello World";
7// type is `"Hello World"`: this is a constant
8// variable and can only represent one value
9
10// using a method to change the string
11// like `.reverse()` will simply change
12// the type to a `string`

Conclusion

The TypeScript documentation has a good

, 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 (there's a good guide by ) 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.

Comments

0

You need to be signed in to comment