.ts files whose only imports and exports are type-only run as ES modules, without require or module

Open
#909 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@darcyrush is already working on this.

Since Nov 6, 2026.

  • #910 by @darcyrush — open

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
node.js, typescript
Domain
backend, devtools

Research direction

Start with src/lib.rs, where parsed_as_esm counts type-only declarations as module syntax, then trace the load hook and TypeScript transform described in the issue. Check how the transform handles files whose imports or exports are erased, including export =. Done means the repro runs as CommonJS and the listed type-only declaration forms behave as expected; linked pull request #910 is already open.

Written by the indexing model from the issue text.

Description

While investigating #905 the LLM stated it found another tangential bug. However, one of the impacted tests marked the logic as intentional, so could be a false positive.

Versions: oxc-project/oxc-node main (ffa98c1), @oxc-node/core 1.0.1, Node.js v26.12.1, linux-x64

Repro

package.json (or no "type")

{ "type": "commonjs" }

types.ts

export type Platform = string;

entry.ts

import type { Platform } from "./types";

const os = require("node:os");
const platform: Platform = os.platform();
console.log("ok", typeof platform);
node --import @oxc-node/core/register ./entry.ts

Expected: ok string. Type erasure removes the import type, and nothing else in the file is module syntax, so Node.js' own type stripping (node ./entry.ts) runs it as CommonJS and prints ok string. tsc with module: nodenext emits CommonJS for it too.

Actual:

ReferenceError: require is not defined in ES module scope, you can use import instead

The same happens when the file is require()d from a .cjs file or imported from an .mts file, and with every declaration that type erasure removes whole: export type { … } (with or without from), export type * from, export type X = …, export interface, export default interface and export declare ….

With export =, the file fails earlier:

import type { Platform } from "./types";

const platform: Platform = process.platform;
export = { platform };
Error: Failed to transform …/counter.ts:
  ! TS(1203): Export assignment cannot be used when targeting ECMAScript modules.

When it is require()d, the error is ReferenceError: module is not defined in ES module scope.
tsc compiles it to module.exports = { platform };.

Cause

oxc's parser resolves a file with a type-only import/export to a module, and parsed_as_esm (src/lib.rs) counts those declarations as module syntax, so the load hook reports the file as an ES module. On the require() path, the TypeScript transform appends an empty export {} when it erases the file's last import/export, so the output is an ES module there as well.

Dominant language
TypeScript
Stars
275
Forks
10
Avg merge
5h 31m
Merged PRs (30d)
68

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from oxc-project/oxc-node

All issues in oxc-project/oxc-node

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.