-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #197 from arethetypeswrong/named-exports
Named exports
- Loading branch information
Showing
39 changed files
with
2,430 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@arethetypeswrong/core": minor | ||
"@arethetypeswrong/cli": minor | ||
--- | ||
|
||
New problem kind: **Named exports cannot be detected by Node.js**. Thanks @laverdet! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# 🕵️ Named ESM exports | ||
|
||
TypeScript allows ESM named imports of the properties of this CommonJS module, but they will crash at runtime because they don’t exist or can’t be statically detected by Node.js in the JavaScript file. | ||
|
||
## Explanation | ||
|
||
When you import a CommonJS module in Node.js, the runtime uses [cjs-module-lexer](https://github.com/nodejs/cjs-module-lexer) to determine what properties of the target’s `module.exports` can be accessed with named imports. This problem is detected by running cjs-module-lexer over the JavaScript and comparing the list of exports it finds with the list of (value, non-type-only) exports exposed in the type declaration file. This problem is only issued when the _types_ contain exports not found in the _JavaScript_, not vice versa. (That is, it’s ok for types to be incomplete, but not to declare exports that don’t exist at runtime.) | ||
|
||
## Consequences | ||
|
||
Node.js will crash at startup when accessing the missing exports as named imports: | ||
|
||
```ts | ||
import { a } from "./api.cjs"; | ||
// SyntaxError: Named export 'a' not found. The requested module './api.cjs' is a CommonJS module, | ||
// which may not support all module.exports as named exports. | ||
|
||
import api from "./api.cjs"; | ||
api.a; // Ok | ||
``` | ||
|
||
## Common causes | ||
|
||
### Incorrect types | ||
|
||
If the types were written by hand, it’s possible that they contain exports that just don’t exist at all in the JavaScript. | ||
|
||
### Unanalyzable JavaScript | ||
|
||
The static analysis supported by cjs-module-lexer is somewhat limited; for example, this works: | ||
|
||
```js | ||
// api.cjs | ||
exports.a = "a"; | ||
|
||
// main.mjs | ||
import { a } from "./api.cjs"; | ||
``` | ||
|
||
but this does not: | ||
|
||
```js | ||
// api.cjs | ||
module.exports = { | ||
a: "a", | ||
}; | ||
|
||
// main.mjs | ||
import { a } from "./api.cjs"; | ||
``` | ||
|
||
However, TypeScript has no way of knowing, and no way of indicating in a declaration file, whether CommonJS exports are written in a way that will be statically analyzable. It assumes they _will_ be, and so even a completely correct declaration file for `api.cjs` will indicate that `a` can be imported by name. Since there’s no way to make the types more restrictive without making them incomplete, and since the unalyzable export is an inconvenience for all consumers of the JavaScript, the only solution is to fix the JavaScript. If the JavaScript exports can’t be restructured, it’s possible to “hint” the exports to cjs-module-lexer with an assignment that never executes: | ||
|
||
```js | ||
module.exports = { | ||
a: "a", // can't understand this... | ||
}; | ||
|
||
0 && | ||
(module.exports = { | ||
a, // but it can understand this, even though it will never run | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,5 +23,10 @@ | |
"engines": { | ||
"node": ">=18", | ||
"pnpm": ">=8" | ||
}, | ||
"pnpm": { | ||
"patchedDependencies": { | ||
"[email protected]": "patches/[email protected]" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ $ attw [email protected] --entrypoints . jsx-runtime | |
vue v3.3.4 | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. Use --json to see the imports that failed to resolve. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🎭 Import resolved to a CommonJS type declaration file, but an ESM JavaScript file. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ $ attw [email protected] --entrypoints vue | |
vue v3.3.4 | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. Use --json to see the imports that failed to resolve. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
┌───────────────────┬──────────────────────────────┐ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ $ attw [email protected] --exclude-entrypoints macros -f ascii | |
vue v3.3.4 | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. Use --json to see the imports that failed to resolve. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🎭 Import resolved to a CommonJS type declaration file, but an ESM JavaScript file. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,12 +6,14 @@ $ attw [email protected] --include-entrypoints foo -f ascii | |
vue v3.3.4 | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🥴 Import found in a type declaration file failed to resolve. Either this indicates that runtime resolution errors will occur, or (more likely) the types misrepresent the contents of the JavaScript files. Use --json to see the imports that failed to resolve. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/InternalResolutionError.md | ||
🎭 Import resolved to a CommonJS type declaration file, but an ESM JavaScript file. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md | ||
💀 Import failed to resolve to type declarations or JavaScript files. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/NoResolution.md | ||
🕵️ TypeScript allows ESM named imports of the properties of this CommonJS module, but they will crash at runtime because they don’t exist or can’t be statically detected by Node.js in the JavaScript file. Use --json to see the list of exports TypeScript can see but Node.js cannot. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/NamedExports.md | ||
"vue" | ||
|
@@ -89,7 +91,7 @@ bundler: 🟢 (JSON) | |
node10: 🟢 | ||
node16 (from CJS): 🟢 (CJS) | ||
node16 (from ESM): 🟢 (CJS) | ||
node16 (from ESM): 🕵️ Named exports | ||
bundler: 🟢 | ||
*********************************** | ||
|
Oops, something went wrong.