TypeScript "No overload matches this call."
This is normally an easy problem to fix. However, when it isn't easily fixed, trying to find the solution is difficult because the cause is typically not obvious.
TL;DR
This example here is one manifestation of such problems seen with TypeScript. Here, the problem occurs when FormData
is used together with Object.fromEntries
. E.g.
const form = evt.target as HTMLFormElement;
const formData = new FormData(form);
const data = Object.fromEntries(formData);
The IDE shows a wriggly line on formData
with the following message:
No overload matches this call.
Overload 1 of 2, '(entries: Iterable<readonly [PropertyKey, any]>): { [k: string]: any; }', gave the following error.
Argument of type 'FormData' is not assignable to parameter of type 'Iterable<readonly [PropertyKey, any]>'.
Property '[Symbol.iterator]' is missing in type 'FormData' but required in type 'Iterable<readonly [PropertyKey, any]>'
Two things to check:
- Ensure that in tsconfig.json, the
lib
option contains minimally these two values in the array:DOM
andDOM.Iterable
(case-insensitive). - If the tsconfig.json file contains the
references
option, check thelib
option in the locations specified underreferences
as well.
Introduction
TypeScript is a language that is based on JavaScript. Its website says that it is "JavaScript with syntax for types".
Indeed, after switching to use TypeScript, I've had the number of runtime issues reduced drastically compared to using JavaScript.
JavaScript has gained widespread adoption due in large part to the ease in which beginning developers can get started. The popularity also meant that different browsers have different JavaScript runtimes that support different versions of the language (though that's less of a problem nowadays since many have chosen to use the Chromium base). There are also various Web APIs that are implemented in JavaScript.
This wide adoption truly speaks for the flexibility of the language but because it is so open, it can be difficult to identify exactly which API and properties/functions are available.
This is where TypeScript benefits the developer greatly. Its typed nature means that integrated development environments (IDEs) can expose productivity enhancements such as code hints and autocompletion.
What's the issue?
For TypeScript to support the differing levels of the specification as well as the myriad libraries that are now available in JavaScript, it requires the use of a config file that is named tsconfig.json which is typically found in the root of the source project folder.
Learning all the options in tsconfig is an endeavour in and of itself.
I'd bet that most TypeScript developers (like, the overwhelming majority), myself included, know the syntax well, but not the configuration of tsconfig. In our defence, it is rare that tsconfig.json ever needs to be modified in the lifetime of a project once it is set up.
Having the correct options set will yield huge productivity benefits for the developer. Conversely, a wrongly configured file can create unexpected headaches.
One common problem is the error hints shown in the IDE.
Problem 1
I have two machines, one Linux and one MacOS (M1), that I develop on.
With the same codebase on one machine, everything works fine. When I check out the repository on the other machine, I see this wriggly line error in VS Code.
The first thought that comes to mind is that there must be some issues with tsconfig.json. It's not a pleasant thought. Trying to fix issues with tsconfig is a trial-and-error most of the time.
Luckily, the cause of the error is sometimes very simple. In this case, the dependencies have not been installed. This is indicated by the wrigglies on the import statements like so:
Errors on all the import statements of npm packages mean that the dependencies have not been installed yet. In this case, the resolution is to simply install the dependencies first.
Solution to problem 1
- npm
- pnpm
npm install
pnpm install
Install dependencies as the first resolution.
When you are stuck on some problem it can be easy to forget to install the dependencies on a freshly checked out codebase.
Furthermore, if there are no import
statements in the file with the error, it is even less obvious.
This is why I've adopted the heuristic of always running npm install
/pnpm install
first.
Problem 2
I am working on two TypeScript projects - one is a Next.js project, and the other is a codebase for a Chrome extension.
In both projects, I have the following code:
const form = evt.target as HTMLFormElement;
const formData = new FormData(form);
const data = Object.fromEntries(formData);
The code looks fine in the Next.js project.
But, in the Chrome extension project, the IDE complains:
Now, this happens after installing the dependencies so it's no longer just an easy fix of installing the dependencies.
Back to basics then. So the error says that Argument of type 'FormData' is not assignable to parameter of type 'Iterable<readonly [PropertyKey, any]>'.
This seems to suggest that the same FormData
class in the extension codebase is of a different version from that in the Next.js codebase. I'm guessing this has to do with the version of TypeScript target or library specified in tsconfig.json
Project | Option | Value |
---|---|---|
Next.js | target | "es5" |
lib | ["dom", "dom.iterable", "esnext"] | |
Extension | target | "ES2020" |
lib | ["ES2020", "DOM", "DOM.Iterable", "WebWorker"] |
Looking at target
, the version stated in Next.js (es5
) is even older than the version in the extension codebase (ES2020
). target
can't be the problem then.
How about lib
? In Next.js we're seeing esnext
whereas in the Chrome extension codebase, we're seeing ES2020
. Could this be it?! esnext
refers to the latest specifications so this should be the problem right?!
Attempted solution 1 to problem 2
So I changed lib
. From this:
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable", "WebWorker"],
"module": "ESNext",
to this:
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],
"module": "ESNext",
After saving this, the error persists.
"Okay," I'm thinking. "Let's just restart the TypeScript server for the change to take effect."
Nope. Error still shows in the IDE.
I've even tried variations like:
- Removing
DOM.Iterable
, restarting TS Server, then adding back in. - Place
DOM.Iterable
last in the array. - Change to lowercase and place
dom.iterable
first in the array.
And restarting TS Server after every change.
I didn't think that these will fix the problems but I had to try them when I was running out of ideas.
Attempted solution 2 to problem 2
Alright. Let's inspect the other options in tsconfig.json.
Option | Next.js Value | Extension Value |
---|---|---|
allowJs | true | not set |
skipLibCheck | true | true |
strict | true | true |
forceConsistentCasingInFileNames | true | not set |
noEmit | true | true |
esModuleInterop | true | not set |
module | esnext | ESNext |
moduleResolution | node | bundler |
resolveJsonModule | true | true |
isolatedModules | true | true |
jsx | preserve | react-jsx |
incremental | true | not set |
paths | { "~src/*": ["./src/*"], "~public/*": ["./public/*"] } | not set |
Nothing stands out as to what could be the cause. So I copied the values over to make the options identical in both projects. No bueno.
Okay. Since the configurations are all the same already, let's take a closer look at the problem. It says that Property '[Symbol.iterator]' is missing in type 'FormData' but required in type 'Iterable<readonly [PropertyKey, any]>'.
So this means that the FormData
class used in the extension codebase does not have the properties to be Iterable
. Why?
Attempted solution 3 to problem 2
Ctrl/Cmd-clicking on the FormData
class reveals two differences:
Code in Node.js
Code in extension codebase
In the Node.js codebase, there is a reference to lib.dom.iterable.d.ts
whereas in the extension codebase, this is not present.
This makes sense since what is missing is the iterable property of FormData
.
The second difference is that the Node.js codebase references @types+react@18.2.73
whereas the extension codebase references @types+react@18.2.48
.
Could that be it?
Let's compare the package.json files of both codebases:
Codebase | Dependency |
---|---|
Next.js | "@types/react": "^18.2.12", |
Extension | "@types/react": "^18.2.43", |
At this point it is worth highlighting that the codebases are using pnpm
and not npm
.
So there is a disparity between the versions. I'm not exactly sure what is going on, so I'm installing the latest version of @types/react
for the extension codebase:
pnpm add -D @types/react@latest
After restarting the TS Server, the wriggly is still there. 😡
Attempted solution 4 to problem 2 - StackOverflow
Next, I took to StackOverflow (being sceptical that AI could solve this problem).
This answer that I've found is answering the question why VS Code is not honouring the options in tsconfig.json. I'm not entirely sure this is the same problem, but at this stage, I'm willing to try anything.
So I added "typescript.tsdk": "node_modules/typescript/lib"
to .vscode/settings.json.
After restarting TS Server, the problem persists. 🤬
Attempted solution 5 to problem 2 - ChatGPT
Alright. Next up, AI. Let's see what this jobs-killer, revolutionary technology can do in this case.
Me:
VS Code is not reading lib.dom.iterable.d.ts for my TypeScript project. How can I solve this problem?
ChatGPT gave a few suggestions. Let's break them down:
ChatGPT:
To resolve the issue of VS Code not reading lib.dom.iterable.d.ts for your TypeScript project, follow these steps:
1. Check TypeScript Version:
Ensure you are using an up-to-date version of TypeScript. Update TypeScript globally and locally in your project if necessary.
npm install -g typescript
npm install typescript --save-dev
Codebase | Dependency |
---|---|
Next.js | "typescript": "^5.1.3", |
Extension | "typescript": "^5.2.2" |
Huh. The extension is already using a newer version of TypeScript.
ChatGPT:
2. Update VS Code:
Make sure you are using the latest version of Visual Studio Code. Updates often include fixes for issues like this.
Well, I'm already on the latest version on both of my machines, and the same problem occurs on both of them.
ChatGPT:
3. Check tsconfig.json:
Ensure your
tsconfig.json
file includes the necessary library references. Yourtsconfig.json
should have a section like this:{
"compilerOptions": {
"lib": ["dom", "es2015", "dom.iterable"]
}
}This explicitly includes dom.iterable as part of the TypeScript compilation process.
Yes, that's the first thing I've checked. (See Attempted solution 1)
ChatGPT:
4. Ensure TypeScript is Correctly Configured in VS Code:
Sometimes, VS Code may use a different TypeScript version than the one installed in your project. To ensure VS Code uses the correct version:
- Open the command palette (Ctrl+Shift+P or Cmd+Shift+P).
- Type and select "TypeScript: Select TypeScript Version".
- Choose "Use Workspace Version" to make sure it uses the TypeScript version specified in your project.
Non-starter. No such option.
Let's give it the benefit of the doubt - it might referring to a Workspace setting.
Oh! Tried this already. 😐
ChatGPT:
5. Reload VS Code Window:
After making changes to
tsconfig.json
, reload the VS Code window to ensure the new configuration is applied.
- Open the command palette and type "Reload Window", then select it.
Reload VS Code? I had been using Windows in my previous life. Of course I had reloaded VS Code already.
ChatGPT:
6. Verify File Presence:
Ensure the
lib.dom.iterable.d.ts
file is present in thenode_modules/typescript/lib
directory. If it's missing, reinstall TypeScript:npm install typescript --save-dev
Yup it's there. And still using the setting "typescript.tsdk": "node_modules/typescript/lib"
.
What if I remove this line? Problem's still there. 😤
ChatGPT:
7. Check for Extensions:
Some extensions can interfere with TypeScript's configuration. Try disabling extensions one by one to see if any are causing the issue.
Not useful. I'm using the same editor with the same set of extensions on two projects giving two different behaviour.
ChatGPT:
8. Clear VS Code Cache:
Sometimes, clearing the TypeScript server's cache can resolve issues. You can do this by:
- Deleting the .
vscode
directory in your project.- Restarting VS Code.
By following these steps, you should be able to resolve the issue of VS Code not reading
lib.dom.iterable.d.ts
in your TypeScript project.
Restarted already lah!
Attempted solution 6 to problem 2 - Meta AI
Me:
VS Code is not reading lib.dom.iterable.d.ts for my TypeScript project. How can I solve this problem?
Meta AI:
Here are some steps you can take to troubleshoot why VS Code is not reading lib.dom.iterable.d.ts for your TypeScript project ¹ ² ³ ⁴:
- Ensure that your .d.ts file is open in your VS Code window for the changes to take effect.
- Make sure your tsconfig.json file is in the root directory, as VS Code will only read files in this directory.
- Try running the command "Reload Window" to see if this resolves the issue.
- Check that your .d.ts file is in the correct directory and that the file path is correct in your tsconfig.json file.
- Make sure that you are not skipping the library check in your tsconfig.json file by setting "skipLibCheck": false.
- If you are still having trouble, try restarting the TypeScript server or VS Code to see if this resolves the issue.
The only things that are new as suggested by Meta AI are the "Reload Window" command and setting "skipLibCheck": false
. Both of which didn't solve the problem.
Attempted solution 7 to problem 2 - good ol' Google Search
First result from StackOverflow had many of the attempted solutions listed.
Time for something more drastic. I closed the editor, removed the entire node_modules directory, ran pnpm install
, then started the editor back up again.
No luck 🫤
Attempted solution 8 to problem 2 - include
This is the "I'll try anything" stage.
The include
field in tsconfig.json did not specify the .ts
and .tsx
files in the extension codebase. Maybe the configuration is sensitive that way?
Option | Value |
---|---|
Original | ["src"] |
Changed | ["**/*.ts", "**/*.tsx"] |
Result: Nope. ❌
Attempted solution 9 to problem 2 - exclude
Another "I'll try anything" attempt.
I noticed that in the Next.js project, the node_modules
directory was excluded.
Project | Option | Value |
---|---|---|
Next.js | 'exclude' | ["node_modules"] |
Extension | 'exclude' | "exclude": ["src/**__tests__/*"] |
So in this attempt, I'm adding node_modules
to exclude
:
"exclude": ["src/**__tests__/*", "node_modules"]
Of course this didn't work — I don't expect it to. 🙄
Attempted solution 10 to problem 2 - project references
Grasping at straws now.
I noticed another difference between the two tsconfig.json files.
Project | Option | Value |
---|---|---|
Next.js | references | not set |
Extension | references | [{ "path": "./tsconfig.node.json" }] |
The tsconfig.node.json file in the extension codebase looks like this:
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"paths": {
"~src/*": ["./src/*"],
"~assets/*": ["./src/assets/*"],
"~pages/*": ["./src/pages/*"],
"~public/*": ["./src/public/*"]
},
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "src", "scripts", "plugins"]
}
Huh. There's no lib
option here. Could that be it? What if I added lib
to this config file?
{
"compilerOptions": {
"composite": true,
"lib": ["DOM", "DOM.Iterable"],
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"paths": {
"~src/*": ["./src/*"],
"~assets/*": ["./src/assets/*"],
"~pages/*": ["./src/pages/*"],
"~public/*": ["./src/public/*"]
},
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "src", "scripts", "plugins"]
}
😱 🎊 🎉
Took me four hours on a Sunday to figure it out and to write this post but I got it!
For whatever reason, the referenced project (tsconfig.node.json) is the one that VS Code is taking cue from instead of the one at the root (tsconfig.json).
No need for all the changes described in attempted solutions 1 to 8. All that's needed is just this one line "lib": ["DOM", "DOM.Iterable"]
in the right file.
I had read project references before but never understood it well enough to internalise it. It's probably something I will procrastinate again until the next problem with tsconfig crops up. Again.
On a related note, there is also jsconfig.json that is essentially tsconfig.json with "allowJs": true