You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I think because it's still experimental
Also definition for node:readline/promises is not available
Reacted by xiaocai-rookie
Reacted by Umed Khudoiberdiev, Cody Ebberson, Alex, Ryan Killeen, pparke, Robin Thomas, Reda Al Sulais, danyreyna, Christophe Hurpeau, Neboer and 4 more
@SimonSchick any chance we can get fetch added anytime soon? it's a really important thing to have in the types
Reacted by Denis Mukhametov, Jesús Leganés-Combarro, Joonas Lehtisyrjä, Gabriel, Victoria Rodriguez, Daniel Morrison, Nathan Nelson, Daniel Lauzon, Mehulkumar, Anton and 15 more
The problem is still that dom libs are not modularized, if they were node typings could just reference dom specs.
As this time I'd rather not copy & paste the API definitions into node as that could create future liabilities.
The problem is still that dom libs are not modularized, if they were node typings could just reference dom specs.
As this time I'd rather not copy & paste the API definitions into node as that could create future liabilities.
Agree on that. Can you point us where it's defined so we can copy it ourselves in our projects, meanwhile it get added to Node.js definitions?
I think it's better to not to use fetch Api in node. But if U need it ( for any reason ) it's seems easy to define one:
declarefunctionfetch(...): ...;
open a new file ( js or ts ) that fetch already available
Command + Click or Ctrl + Click on fetch ( goto definition )
Copy and paste the types to source file
If you dont wanna see it in your ts files you can just simply create types.d.ts file ( name is important ) or create a folder @types ( name is important ) and put it on that folder
Note: your d.ts ( definition file ) must not be a module if it is, you have to import the fetch type in every file that you are using it.
Reacted by Joe Hillenbrand, Horiuchi Hiroki, Andrew, Cynthia Rey, Daniel Morrison, ravshansbox, Pionxzh, Marat A. Denenberg, Umed Khudoiberdiev, Andrea Cigana and 77 more
Reacted by Victoria Rodriguez, Vladislav Botvin, mattpeng, 流浪大法师, Yudai Nakata, Philippe and Alejandro Marco
2. Node@18 is not even the LTS version, it's the latest, not the most stable one
It's the most stable one, just only doesn't have yet the LTS denomination. I could agree that odd versions (v17, v19...) are unstable development versions and should not be used on production, but pair ones (v16, v18) is totally fine.
Reacted by Victoria Rodriguez, CaioGiasson and 流浪大法师
Yeah, node 18 will be LTS in two months (2022-10-25).
The problem is still that dom libs are not modularized, if they were node typings could just reference dom specs. As this time I'd rather not copy & paste the API definitions into node as that could create future liabilities.
@SimonSchick, so are we expecting lib.dom to be modularized before we can add node typings for fetch? Sounds like something that might take a while.
I wonder if in the meanwhile we could add fetch to types/node by copy-pasting fetch, Request, Response, Headers etc. definitions as a standalone module that would be easy to delete when it's possible to just reference the respective DOM definitions.
I wonder if in the meanwhile we could add fetch to types/node by copy-pasting fetch, Request, Response, Headers etc. definitions as a standalone module that would be easy to delete when it's possible to just reference the respective DOM definitions.
Agree, and add a TODO: comment about that fact, or maybe also store them in an independent types file and reference it from the lib.dom types... starting with the modularization ourselves :-)
Well DT is good for packages that don't have types already but for packages that do, or are otherwise written in TS, DT is usually the worse of the two options due to desynchronization. If there could be a way to extract types at build time, prior to publishing, that'd be the 'ideal' way depending on how you look at things.
Reacted by Madeline Gurriarán, Kei Son and Natan Pereira
It seems to me that this points to a fundamental problem with how TypeScript handles type definitions, particularly with global types. The actual TypeScript team should be more involved in this discussion.
I think the best solution today is to use a clever combination of the lib and types settings within multiple tsconfig files in a single project.
An example web project might have 3 "environments" that are used by various files: a "web" environment for production code that will run in a browser, a "test" environment that runs in Node (or Deno or Bun) and polyfills web APIs using something like happy-dom or jsdom, and a "server" environment that includes everything running in a regular Node (or Deno or Bun) environment with no web APIs.
This project can handle the differences in available global APIs and modules by defining 3 separate tsconfig files with explicitly defined lib and types settings:
tsconfig.web.json:
"lib": ["dom", "dom.iterable", "..."]
"types": [] (explicitly declare no types to be included)
"include": ["./client"]
"exclude": ["./client/**/__tests__"] (exclude tests, which are covered below)
tsconfig.node.json:
"lib": ["..."] (no DOM APIs are available)
"types": ["node"] (explicitly include only Node types)
"include": ["./server", "..."] (add whatever other files run in Node, like webpack.config.ts or vite.config.ts)
tsconfig.test.json:
"lib": ["dom", "dom.iterable", "..."]
"types": ["node"] (explicitly include only Node types)
"include": ["./client/**/__tests__"] (only include tests)
This solves most of the problem, notably for files that run only on the web or only in Node. However, the "test" environment has both DOM and Node types. Technically we can't know which fetch types are correct, since any DOM polyfill that is used may or may not overwrite Node's built-in fetch implementation.
TypeScript's solution for this problem up to this point has been to merge both definitions into one. This works well for interfaces, which will simply accept properties from both definitions. It does not work well for functions, however. We already see this problem with setTimeout. The DOM types return a number, while the Node types return a NodeJS.Timeout. The simple workaround on the web side is to use window.setTimeout, which resolves to only the DOM version. But there is no good solution on the Node side. In the case of setTimeout things typically just happen to work, but if there was a more complicated difference between the types, this would have been a problem ages ago.
As more and more web APIs are added to non-browser environments, this problem is likely to only get worse. For example, since fetch was designed to work in the browser sandbox, it supports only a subset of HTTP (e.g. no direct access to all cookies), so some environments add additional properties to the options object passed to fetch. Other web APIs are likely to have similar situations.
We need the ability to more finely tune what an environment looks like, down to selecting individual items from various type definitions. This might be possible using conditional types and Pick and Omit, but those don't really feel "first-class" IMO. I'd like to hear what other people's thoughts are on this.
Reacted by Roger Schönbächler, Paul Draper, David Brownman, Kei Son, Dmitry Semigradsky and Linus Björklund
The actual TypeScript team should be more involved in this discussion.
😕
Oops! I didn't notice that someone from the TypeScript team was already here! I read the earlier comments more thoroughly than the latter ones, so I completely missed your responses. I'm sorry if I offended anyone.
No worries 😄 I think you’ll find some of those links interesting. I think this issue is probably not the best place to go deep into the weeds on rethinking environmental types from the ground up. I broadly agree with you, and this problem used to be very much top-of-mind for me. But from my perspective, each time we’ve hit a wave of global type clashes that seems really intractable, we’ve actually been able to resolve things pretty well with the tools we already have. The PR I have up to add fetch typings, closing this issue, is an example. It’s not perfect but it’s really close, I think. Another one:
In the case of setTimeout things typically just happen to work
Again, it’s not perfect, but it doesn’t provide a super strong justification for overhauling the way global types work. We just try our best, through DT contributions, to discourage Node.js-related typings from pulling in the DOM unnecessarily and vice versa, so users can hopefully avoid having @types/node and lib.dom.d.ts in the same compilation, while ensuring they’re written in a way that doesn’t explode into errors when they are in the same compilation. And this continues to mostly work out for most cases.
I would love to have a more rigorous solution in the future, but it’s definitely not worth holding off on adding fetch while we wait for a silver bullet.
#66824 is ready. It only updates v20 typings due to a test infrastructure limitation that will likely be resolved within a couple weeks. I’d like to wait for a non-TS team @types/node maintainer to approve.
Reacted by ExE Boss, Nikita Fuchs, Simon and DevSide
Reacted by Denis Mukhametov, Marek Lukáš, Amir Muhammad Hakim, Daniel Nagy, Cody Ebberson, Mia Celeste and ExE Boss
Reacted by Martin Janeček, Madeline Gurriarán, Nicu Chiciuc, AverageHelper, Saad Khan, Eric K., Daniel Sarsi Orta, Julian, danielwerg, Valentin Gurkov and 21 more
Reacted by Denis Mukhametov, Cody Ebberson and ExE Boss
I believe fetch types are pretty good on the latest @types/node@20. Your example looks right to me. You should not need to reference "globalThis" -- just Promise<Response> should typecheck fine -- but it might not be a bad idea if you want to make it very clear that you aren't referring to import { Response } from 'express'.
Apologies for replying to such an old thread, but I am not sure what could be a more suitable place.
In the introduction of these types there was a workaround that allowed the types to roughly correct for pure node applications and applications with code that should be ran in the browser as well. This combination seems to have become an obstacle in my case.
I think I am working with a relatively common setup where I have a TS project with code that runs on node and code that runs int he browser (in this case a next application). With such an application lib.dom.d.ts is likely included in the tsconfig, but even if was not, it's not unlikely for it to be pulled in by some dependency. In essence, for this kind of a project it's difficult to get rid of lib.dom.d.ts.
The presence of lib.dom.d.ts means that the used types are the DOM types. As the original PR states, these are very similar with undici's types. However, there are some difference with one being the omission of the dispatcher field. This field can be use to set a custom agent, which allows custom keepalive settings to be configured.
I've used a better part of the day trying to find the best workaround, but it seems that there are quite a few potholes that can be struck. For instance, importing fetch directly from undici breaks interop with msw.
Ultimately I was able to work around the limitation by using two tsconfig files and tinkering with the settings and project structure until I was able isolate our node fetch integration from lib.dom.d.ts.
Do you have an example of the code that wasn't working in the mixed environment (Node code, with lib-dom included)? I'm wondering if some selective type-casting could have saved you the trouble of multiple tsconfig files. That's probably a good long-term solution, though.
@thw0rted Thank you for the reply. I ended up iterating and did end up going the route you suggested. I ended up installing undici-types and type cast in a few places in order to get the types to cooperate. We have a wrapper on top of the fetch API which made the process easier.
All global types were browser types so whenever we attempted to use node-only-features, we'd have issues. In our case the problem case was adding a dispatcher that changed the default keepalive settings.
I can also vouch that it doesn't feel like a good long-term solution. As we've implemented more functionality to our fetch wrapper, we've come across type issues consistently. In time we'll likely find a better balance in casting and we'll have fewer issues.
The type inconsistencies can be difficult to reason about if you aren't aware of the limitations of the type system. For instance, we ended up breaking instanceof URL checks. I assume it's due to a type cast that's not optimal. Likely we've cast a RequestInfo to be a Undici.RequestInfo (e.g. string | node:url.URL | Undici.Request. When we make the comparison TS sees the URL in instanceof URL to be a browser.URL. It basically results in a scenario like this:
exportconstgetUrl=(url: Undici.RequestInfo)=>{if(typeofurl==='string'){returnurl;}elseif(urlinstanceofURL){returnurl.href;}// @ts-expect-error: TS errors because field 'url' does not exist in 'URL'returnurl.url;};
Can be dealt with by using another cast, but things of this nature tend to pop up while developing.
Activity
mahdi-farnia commentedon Jun 23, 2022
I think because it's still experimental
Also definition for
node:readline/promisesis not availablexiaocai-rookie commentedon Jun 24, 2022
Yes, node official announce too.
shadow-light commentedon Jul 4, 2022
It was simply not added because of time constraints so hopefully sometime soon...
SuperchupuDev commentedon Jul 17, 2022
@SimonSchick any chance we can get
fetchadded anytime soon? it's a really important thing to have in the typespiranna commentedon Jul 19, 2022
Is it available in any branch or development version we can make use of?
piranna commentedon Jul 21, 2022
I would love to, but my client asked me to use Typescript :-)
SimonSchick commentedon Jul 21, 2022
The problem is still that dom libs are not modularized, if they were node typings could just reference dom specs.
As this time I'd rather not copy & paste the API definitions into node as that could create future liabilities.
piranna commentedon Jul 21, 2022
Agree on that. Can you point us where it's defined so we can copy it ourselves in our projects, meanwhile it get added to Node.js definitions?
mahdi-farnia commentedon Jul 21, 2022
I think it's better to not to use fetch Api in node. But if U need it ( for any reason ) it's seems easy to define one:
If you dont wanna see it in your ts files you can just simply create types.d.ts file ( name is important ) or create a folder
@types( name is important ) and put it on that folderNote: your d.ts ( definition file ) must not be a module if it is, you have to import the fetch type in every file that you are using it.
piranna commentedon Jul 21, 2022
Why not?
That's what I'm asking for.
mahdi-farnia commentedon Jul 21, 2022
piranna commentedon Jul 21, 2022
I would not say @mcollina code is not good, with so much performance obsesive code done...
Node.js is not from Microsoft, Microsoft has only developed Typescript on top of it.
piranna commentedon Jul 21, 2022
Good point, fair enough.
It's the most stable one, just only doesn't have yet the LTS denomination. I could agree that odd versions (v17, v19...) are unstable development versions and should not be used on production, but pair ones (v16, v18) is totally fine.
rjoonas commentedon Aug 10, 2022
Yeah, node 18 will be LTS in two months (2022-10-25).
@SimonSchick, so are we expecting lib.dom to be modularized before we can add node typings for fetch? Sounds like something that might take a while.
I wonder if in the meanwhile we could add fetch to types/node by copy-pasting fetch, Request, Response, Headers etc. definitions as a standalone module that would be easy to delete when it's possible to just reference the respective DOM definitions.
piranna commentedon Aug 10, 2022
Agree, and add a
TODO:comment about that fact, or maybe also store them in an independent types file and reference it from thelib.domtypes... starting with the modularization ourselves :-)113 remaining items
Qix- commentedon Sep 11, 2023
Well DT is good for packages that don't have types already but for packages that do, or are otherwise written in TS, DT is usually the worse of the two options due to desynchronization. If there could be a way to extract types at build time, prior to publishing, that'd be the 'ideal' way depending on how you look at things.
piranna commentedon Sep 12, 2023
Prepublish script?
jchitel commentedon Sep 28, 2023
It seems to me that this points to a fundamental problem with how TypeScript handles type definitions, particularly with global types. The actual TypeScript team should be more involved in this discussion.
I think the best solution today is to use a clever combination of the
libandtypessettings within multiple tsconfig files in a single project.An example web project might have 3 "environments" that are used by various files: a "web" environment for production code that will run in a browser, a "test" environment that runs in Node (or Deno or Bun) and polyfills web APIs using something like
happy-domorjsdom, and a "server" environment that includes everything running in a regular Node (or Deno or Bun) environment with no web APIs.This project can handle the differences in available global APIs and modules by defining 3 separate tsconfig files with explicitly defined
libandtypessettings:tsconfig.web.json:"lib": ["dom", "dom.iterable", "..."]"types": [](explicitly declare no types to be included)"include": ["./client"]"exclude": ["./client/**/__tests__"](exclude tests, which are covered below)tsconfig.node.json:"lib": ["..."](no DOM APIs are available)"types": ["node"](explicitly include only Node types)"include": ["./server", "..."](add whatever other files run in Node, likewebpack.config.tsorvite.config.ts)tsconfig.test.json:"lib": ["dom", "dom.iterable", "..."]"types": ["node"](explicitly include only Node types)"include": ["./client/**/__tests__"](only include tests)This solves most of the problem, notably for files that run only on the web or only in Node. However, the "test" environment has both DOM and Node types. Technically we can't know which
fetchtypes are correct, since any DOM polyfill that is used may or may not overwrite Node's built-infetchimplementation.TypeScript's solution for this problem up to this point has been to merge both definitions into one. This works well for interfaces, which will simply accept properties from both definitions. It does not work well for functions, however. We already see this problem with
setTimeout. The DOM types return anumber, while the Node types return aNodeJS.Timeout. The simple workaround on the web side is to usewindow.setTimeout, which resolves to only the DOM version. But there is no good solution on the Node side. In the case ofsetTimeoutthings typically just happen to work, but if there was a more complicated difference between the types, this would have been a problem ages ago.As more and more web APIs are added to non-browser environments, this problem is likely to only get worse. For example, since
fetchwas designed to work in the browser sandbox, it supports only a subset of HTTP (e.g. no direct access to all cookies), so some environments add additional properties to the options object passed tofetch. Other web APIs are likely to have similar situations.We need the ability to more finely tune what an environment looks like, down to selecting individual items from various type definitions. This might be possible using conditional types and
PickandOmit, but those don't really feel "first-class" IMO. I'd like to hear what other people's thoughts are on this.andrewbranch commentedon Sep 28, 2023
People’s thoughts on this:
domlib events out into separate lib for nodejs use microsoft/TypeScript#43972😕
jchitel commentedon Sep 28, 2023
Oops! I didn't notice that someone from the TypeScript team was already here! I read the earlier comments more thoroughly than the latter ones, so I completely missed your responses. I'm sorry if I offended anyone.
andrewbranch commentedon Sep 28, 2023
No worries 😄 I think you’ll find some of those links interesting. I think this issue is probably not the best place to go deep into the weeds on rethinking environmental types from the ground up. I broadly agree with you, and this problem used to be very much top-of-mind for me. But from my perspective, each time we’ve hit a wave of global type clashes that seems really intractable, we’ve actually been able to resolve things pretty well with the tools we already have. The PR I have up to add
fetchtypings, closing this issue, is an example. It’s not perfect but it’s really close, I think. Another one:Again, it’s not perfect, but it doesn’t provide a super strong justification for overhauling the way global types work. We just try our best, through DT contributions, to discourage Node.js-related typings from pulling in the DOM unnecessarily and vice versa, so users can hopefully avoid having
@types/nodeandlib.dom.d.tsin the same compilation, while ensuring they’re written in a way that doesn’t explode into errors when they are in the same compilation. And this continues to mostly work out for most cases.I would love to have a more rigorous solution in the future, but it’s definitely not worth holding off on adding
fetchwhile we wait for a silver bullet.jchitel commentedon Sep 28, 2023
That makes a lot of sense. The Issues you posted are super interesting and show that others have clearly thought more about this than I have 😅
I agree that there needs to be a solution right now to resolve this particular issue. I'll defer further discussion to your PR.
joshxyzhimself commentedon Oct 5, 2023
For now undici works.
andrewbranch commentedon Oct 5, 2023
#66824 is ready. It only updates v20 typings due to a test infrastructure limitation that will likely be resolved within a couple weeks. I’d like to wait for a non-TS team
@types/nodemaintainer to approve.thw0rted commentedon May 6, 2024
I believe fetch types are pretty good on the latest
@types/node@20. Your example looks right to me. You should not need to reference "globalThis" -- justPromise<Response>should typecheck fine -- but it might not be a bad idea if you want to make it very clear that you aren't referring toimport { Response } from 'express'.Jokinen commentedon Jul 31, 2024
Apologies for replying to such an old thread, but I am not sure what could be a more suitable place.
In the introduction of these types there was a workaround that allowed the types to roughly correct for pure node applications and applications with code that should be ran in the browser as well. This combination seems to have become an obstacle in my case.
I think I am working with a relatively common setup where I have a TS project with code that runs on node and code that runs int he browser (in this case a next application). With such an application
lib.dom.d.tsis likely included in the tsconfig, but even if was not, it's not unlikely for it to be pulled in by some dependency. In essence, for this kind of a project it's difficult to get rid oflib.dom.d.ts.The presence of
lib.dom.d.tsmeans that the used types are the DOM types. As the original PR states, these are very similar with undici's types. However, there are some difference with one being the omission of thedispatcherfield. This field can be use to set a custom agent, which allows custom keepalive settings to be configured.I've used a better part of the day trying to find the best workaround, but it seems that there are quite a few potholes that can be struck. For instance, importing
fetchdirectly fromundicibreaks interop with msw.Ultimately I was able to work around the limitation by using two
tsconfigfiles and tinkering with the settings and project structure until I was able isolate our node fetch integration fromlib.dom.d.ts.thw0rted commentedon Jul 31, 2024
Do you have an example of the code that wasn't working in the mixed environment (Node code, with lib-dom included)? I'm wondering if some selective type-casting could have saved you the trouble of multiple tsconfig files. That's probably a good long-term solution, though.
Jokinen commentedon Aug 16, 2024
@thw0rted Thank you for the reply. I ended up iterating and did end up going the route you suggested. I ended up installing
undici-typesand type cast in a few places in order to get the types to cooperate. We have a wrapper on top of thefetchAPI which made the process easier.All global types were browser types so whenever we attempted to use node-only-features, we'd have issues. In our case the problem case was adding a
dispatcherthat changed the default keepalive settings.I can also vouch that it doesn't feel like a good long-term solution. As we've implemented more functionality to our
fetchwrapper, we've come across type issues consistently. In time we'll likely find a better balance in casting and we'll have fewer issues.The type inconsistencies can be difficult to reason about if you aren't aware of the limitations of the type system. For instance, we ended up breaking
instanceof URLchecks. I assume it's due to a type cast that's not optimal. Likely we've cast aRequestInfoto be aUndici.RequestInfo(e.g.string | node:url.URL | Undici.Request. When we make the comparison TS sees theURLininstanceof URLto be abrowser.URL. It basically results in a scenario like this:Can be dealt with by using another cast, but things of this nature tend to pop up while developing.