nodejs / nodejs/import-in-the-middle
`export const x = expr as Generic<A, B>` produces a phantom export named after `B`, colliding when 2+ such casts share a last type arg
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 170
- Forks
- 58
- Avg merge
- 3d 19h
- Merged PRs (30d)
- 7
Description
import-in-the-middle's ESM export scanner (lib/get-esm-exports.mjs → es-module-lexer) misparses a specific TypeScript cast shape: export const x = expr as GenericType<Arg1, Arg2>;. When the cast target has 2+ comma-separated type arguments, the scanner emits a phantom second export named after the literal text of the last type argument — not tied to any real binding.
Not specific to the word unknown — swapping it for number produces a phantom number export instead. But unknown is exactly what codegen tools emit as the trailing type arg for typed documents with no variables (e.g. graphql-code-generator's typed-document-node plugin: export const MyQueryDocument = {...} as unknown as DocumentNode<MyQuery, unknown>;). Any generated file with 2+ such exports gets two phantom "unknown" exports, which collide in the generated wrapper module — invalid ESM, crashes the module linker before user code runs:
SyntaxError: Duplicate export of 'unknown'
Repro
Full runnable repro: https://gist.github.com/tmair/a10f56297ca85729faabedc897d47918
git clone https://gist.github.com/a10f56297ca85729faabedc897d47918.git phantom-export
Run:
npm install
node --experimental-loader=import-in-the-middle/hook.mjs --import ./register.mjs app.mjs
Expected: 1
Actual:
file:///.../types.ts?iitm=true:16
export { $0 as "foo", $1 as "unknown", $2 as "bar", $3 as "unknown" }
^^^^^^^^^^^^^^^
SyntaxError: Duplicate export of 'unknown'
Environment
import-in-the-middle: reproduces on 3.5.0 and 3.5.1 (latest)- Node.js: v26.3.0 locally; also seen on v24.21.0 in production
- Triggered via Node's native TypeScript execution (running
.tsfiles directly, no separate transpile step) combined with--experimental-loader=import-in-the-middle/hook.mjs
Boundary conditions checked
- Single-arg generic cast (
1 as Array<unknown>) — no phantom export. - Type annotation instead of cast (
const foo: Generic<A, B> = ...) — no phantom export. - Only a cast expression
as Generic<Arg1, Arg2>with 2+ type args triggers it; phantom export name = last type argument's text.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with lib/get-esm-exports.mjs and reproduce the issue using the linked gist and its npm install/node command, then inspect how es-module-lexer handles the multi-argument TypeScript cast. Done means the scanner no longer emits phantom exports for this shape, so the repro prints 1 without a duplicate-export SyntaxError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs, typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100