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
{{ message }}
Repository navigation
import { default as ... } ... doesn't work as of 4.8.3 #50690
@flatten-js/core is a CommonJS module (it ships some ESM files, but these are not exposed through any standard package.json fields). This means when you do a default import of it (or a { default as Whatever } import) in Node, you get the whole module.exports object. @flatten-js/core’s module.exports is an object with roughly the same shape as Flatten, including a member named default whose value is Flatten.
But instead, as you noted, the .d.ts file included says export default Flatten. This is not the same thing. It is, admittedly, really puzzling to try to figure out what export default means when you know from the file extension (.d.ts) and package.json type (omitted entirely) that you are looking at a CommonJS module, not an ES module. But we do our best and say that it represents something like module.exports.default = Flatten. Which is something that the JS file actually has, which is great, but it’s also woefully incomplete. It’s missing every other export besides default, which is why, when you import it, TypeScript shows you that it has a default and nothing else. That’s exactly what the typings say.
Now, you may object, saying that obviously we should just resolve to the default member of the module record here. But that would be incorrect. Consider this perfectly correct JS/.d.ts pair:
What should we say the type of lib is when you import it?
importlibfrom"my-wacky-lib";
By your hypothetical objection, it would look like lib should be "default". But in fact, in Node, it’s an object containing properties foo and default. This is different from what runtimes/transpilers/bundlers who care about that __esModule flag would give you, so it’s quite important we get this right and warn you that Node is going to return the whole module record.
The author of @flatten-js/core was clever to make module.exports virtually indistinguishable from module.exports.default—it means that consumers will see the same API regardless of whether their module resolver cares about __esModule. Unfortunately, that same clever duplication was not copied into the type declaration file.
The fact that { default as Flatten } worked was a bug, and was causing problems for libraries that are typed correctly: #49567.
Chiming in here - while I understand that the old behavior working correctly may have been unintentional, this change in 4.8.3 led to a bunch of breaking changes in my code, which doesn't seem right for a point release.
The { default as X } clause is useful in working around issues with types when you have an ESM nodenext app and import a RequireJS dependency with a default export whose types haven't yet been updated for nodenext support as suggested in #48845.
to compile. I had to make a bunch of similar changes to fastify plugin imports as well. It looks like ajv is affected as well (ajv-validator/ajv#2047), and likely many other packages.
This seems like a pretty major non-backwards-compatible change for a point release.
Reacted by An Phi, Meowster, Mister-Hope and Nathan Sarang-Walters
Daniil Kulchenko (@dkulchenko) yeah, I understand. We didn’t realize that the bug was being used as a workaround for broken typings. Knowing what I know now, I probably would have held the fix from 4.8.3, but the proverbial toothpaste is out of the tube now.
One correction, though—the typings that are broken were always wrong; they didn’t just need to be updated for nodenext. The problem is just more observable in nodenext. Hopefully the problem libraries will get updated quickly.
Haven't heard this one before! It just sounds so... prosaic, compared to more colorful expressions like the cat being out of the bag, or the genie being out of the bottle, or closing the barn door after the horse escaped...
I'm stuck on a similar situation. I am writing ESM code with TypeScript 4.8.3 and moduleResolution: "Node16". I import a CommonJS library whose code looks like:
// node_modules/@types/sql.js/index.d.tsexportinterfaceInitSqlJsStaticextendsFunction{(config?: SqlJsConfig): Promise<SqlJsStatic>;readonlydefault: this;}declare global {letSqlJs: InitSqlJsStatic;}exportdefaultSqlJs;
...and when I attempt to call someFunc() like this, I run into type errors:
importinitSqlJsfrom'sql.js';// error TS2349: This expression is not callable.// Type 'typeof import("/path/to/my/project/node_modules/@types/sql.js/index")' has no call signatures.initSqlJs();
...even though the code runs fine in Node.js.
If the fault lies with the type definitions for sql.js, how can the type definitions be corrected without altering the JS source itself?
Hi, I'm having the same issue using "typescript": "^4.8.2" with React Native. There's any recommended suggestion on how to fix this or should I downgrade the version :(?
My issue is probably the same with others with export {default as XYZ} from './abcd'
When I'm trying to import the component in other files using the name given with this current version of typescript I cannot make it work because I get an error telling Cannot read properties of undefined (reading 'XYZ').
Hi there, this issue is heavily effecting my projects.
I am targeting pure esm packages with target: es2020 (compatible with node14) and moduleResolution: NodeNext in my project.
There is a lot of packages in my repo with is exporting both esm files with exports and module and cjs files with main, but not having type: module or even use type: commonjs
I can only managed to fix types issues with them by adding type: module. My concern is:
Is this solution correct? Does this have side effects?
Is this internal changes being so breaking?
With just one hour, I am already sending severl prs to upsteam. including:
The examples above are popular packages,(e.g.: mitt is getting Weekly Downloads at 1,960,326). If the whole ecosystem has a huge part that needs to change according to this, I am thinking that the change might be too breaking for a minor version.
Activity
andrewbranch commentedon Sep 9, 2022
TL;DR: the library’s types are wrong.
@flatten-js/core is a CommonJS module (it ships some ESM files, but these are not exposed through any standard package.json fields). This means when you do a default import of it (or a
{ default as Whatever }import) in Node, you get the wholemodule.exportsobject. @flatten-js/core’smodule.exportsis an object with roughly the same shape asFlatten, including a member nameddefaultwhose value isFlatten.The way you represent this in a
.d.tsfile is something like this:But instead, as you noted, the
.d.tsfile included saysexport default Flatten. This is not the same thing. It is, admittedly, really puzzling to try to figure out whatexport defaultmeans when you know from the file extension (.d.ts) and package.jsontype(omitted entirely) that you are looking at a CommonJS module, not an ES module. But we do our best and say that it represents something likemodule.exports.default = Flatten. Which is something that the JS file actually has, which is great, but it’s also woefully incomplete. It’s missing every other export besidesdefault, which is why, when you import it, TypeScript shows you that it has adefaultand nothing else. That’s exactly what the typings say.Now, you may object, saying that obviously we should just resolve to the
defaultmember of the module record here. But that would be incorrect. Consider this perfectly correct JS/.d.ts pair:What should we say the type of
libis when you import it?By your hypothetical objection, it would look like
libshould be"default". But in fact, in Node, it’s an object containing propertiesfooanddefault. This is different from what runtimes/transpilers/bundlers who care about that__esModuleflag would give you, so it’s quite important we get this right and warn you that Node is going to return the whole module record.The author of @flatten-js/core was clever to make
module.exportsvirtually indistinguishable frommodule.exports.default—it means that consumers will see the same API regardless of whether their module resolver cares about__esModule. Unfortunately, that same clever duplication was not copied into the type declaration file.The fact that
{ default as Flatten }worked was a bug, and was causing problems for libraries that are typed correctly: #49567.andrewbranch commentedon Sep 9, 2022
Wesley Wigham (@weswigham), please double check my explanation 😅
dkulchenko commentedon Sep 9, 2022
Chiming in here - while I understand that the old behavior working correctly may have been unintentional, this change in 4.8.3 led to a bunch of breaking changes in my code, which doesn't seem right for a point release.
The
{ default as X }clause is useful in working around issues with types when you have an ESMnodenextapp and import a RequireJS dependency with a default export whose types haven't yet been updated fornodenextsupport as suggested in #48845.For example, see the ioredis ESM import snippet (which was correct as of 4.8.2 but no longer works): https://github.com/luin/ioredis#basic-usage
This worked in 4.8.2:
but is broken in 4.8.3, needing to be rewritten as:
to compile. I had to make a bunch of similar changes to fastify plugin imports as well. It looks like ajv is affected as well (ajv-validator/ajv#2047), and likely many other packages.
This seems like a pretty major non-backwards-compatible change for a point release.
alecmev commentedon Sep 9, 2022
Thank you for such a thorough explanation, Andrew Branch (@andrewbranch)! I'll report this in Flatten instead.
andrewbranch commentedon Sep 9, 2022
Daniil Kulchenko (@dkulchenko) yeah, I understand. We didn’t realize that the bug was being used as a workaround for broken typings. Knowing what I know now, I probably would have held the fix from 4.8.3, but the proverbial toothpaste is out of the tube now.
One correction, though—the typings that are broken were always wrong; they didn’t just need to be updated for
nodenext. The problem is just more observable innodenext. Hopefully the problem libraries will get updated quickly.fatcerberus commentedon Sep 11, 2022
Haven't heard this one before! It just sounds so... prosaic, compared to more colorful expressions like the cat being out of the bag, or the genie being out of the bottle, or closing the barn door after the horse escaped...
meteorlxy commentedon Sep 16, 2022
The workaround becomes even stranger than before 😅
Update: the workaround seems only works for type checking, but the compiled result would failed to be used in other tools like Vite
pastelmind commentedon Sep 20, 2022
I'm stuck on a similar situation. I am writing ESM code with TypeScript 4.8.3 and
moduleResolution: "Node16". I import a CommonJS library whose code looks like:and whose type definitions look like:
...and when I attempt to call
someFunc()like this, I run into type errors:...even though the code runs fine in Node.js.
If the fault lies with the type definitions for
sql.js, how can the type definitions be corrected without altering the JS source itself?andrewbranch commentedon Sep 20, 2022
It seems like they’re trying to do a UMD module
[sql.js] fix export for Node16 and browser scripts
🤖 Merge PR #62346 [sql.js] fix export format for Node16 and browser e…
chore: bump typescript to latest and fix compilation issues
chore: bump typescript to latest and fix compilation issues
Mihai-github commentedon Sep 29, 2022
Hi, I'm having the same issue using
"typescript": "^4.8.2"with React Native. There's any recommended suggestion on how to fix this or should I downgrade the version :(?andrewbranch commentedon Sep 29, 2022
Mihai (@Mihai-github) can you give us some more details on what you’re doing (including tsconfig settings) and what you’re seeing?
Mihai-github commentedon Sep 30, 2022
Adam Burgess (@adamburgess) Sure, thanks.
My tsconfig.json:
My issue is probably the same with others with
export {default as XYZ} from './abcd'When I'm trying to import the component in other files using the name given with this current version of typescript I cannot make it work because I get an error telling
Cannot read properties of undefined (reading 'XYZ').andrewbranch commentedon Sep 30, 2022
What import/re-export is giving you the problem?
GabenGar commentedon Oct 6, 2022
How do I fix this issue for a ESM-only javascript package the types for which are provided by
DefinitelyTyped?The package: https://github.com/yeoman/stringify-object
The types: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/stringify-object
andrewbranch commentedon Oct 13, 2022
GabenGar a package.json with
"type": "module"needs to be added to the DefinitelyTyped package.nickluger commentedon Oct 15, 2022
This works for me... 🤷♂️
Mister-Hope commentedon Nov 19, 2022
Hi there, this issue is heavily effecting my projects.
I am targeting pure esm packages with
target: es2020(compatible with node14) andmoduleResolution: NodeNextin my project.There is a lot of packages in my repo with is exporting both esm files with
exportsandmoduleand cjs files withmain, but not havingtype: moduleor even usetype: commonjsI can only managed to fix types issues with them by adding
type: module. My concern is:With just one hour, I am already sending severl prs to upsteam. including:
The examples above are popular packages,(e.g.: mitt is getting Weekly Downloads at 1,960,326). If the whole ecosystem has a huge part that needs to change according to this, I am thinking that the change might be too breaking for a minor version.
Andrew Branch (@andrewbranch) Could you give some feedback with this?
Mister-Hope commentedon Nov 19, 2022
I read again https://nodejs.org/dist/latest-v18.x/docs/api/packages.html#exports, it seems that my solution adding
type: modulemay break cjs requires, so how shall I solve this? A.d.mtsdeclaration file or what?