oxc-project/oxc · error · OxcDiagnostic
TS1203
TS1203
Error message
Export assignment cannot be used when targeting ECMAScript modules.
What it means
Oxc's port of TypeScript error TS1203: `export = <expression>` (TSExportAssignment, the CommonJS export-assignment form) cannot be emitted when the output module format is ESM. The transform rewrites it to `module.exports = <expression>` at crates/oxc_transformer/src/typescript/module.rs:59-92 and reports the diagnostic when `self.module.is_esm()` (module.rs:65-69). As with TS1202, this fires only when `Module::Esm` is explicitly configured — the default `Module::Preserve` and `Module::CommonJS` do not warn.
Source
Thrown at crates/oxc_transformer/src/typescript/diagnostics.rs:17
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::Span;
#[cold]
pub fn import_equals_cannot_be_used_in_esm(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Import assignment cannot be used when targeting ECMAScript modules.")
.with_help(
"Consider using 'import * as ns from \"mod\"',
'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.",
)
.with_label(span)
.with_error_code("TS", "1202")
}
#[cold]
pub fn export_assignment_cannot_bed_used_in_esm(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Export assignment cannot be used when targeting ECMAScript modules.")
.with_help("Consider using 'export default' or another module format instead.")
.with_label(span)
.with_error_code("TS", "1203")
}
#[cold]
pub fn ambient_module_nested(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Ambient modules cannot be nested in other modules or namespaces.")
.with_label(span)
}
#[cold]
pub fn namespace_exporting_non_const(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Namespaces exporting non-const are not supported by Oxc. Change to const or see: https://oxc.rs/docs/guide/usage/transformer/typescript.html#partial-namespace-support")
.with_label(span)
}
#[cold]View on GitHub (pinned to e1e7af627c)
Solutions
- Replace `export = expr` with `export default expr` (the diagnostic's own help text)
- If consumers rely on the CJS namespace shape (`.default` interop), keep default export and let the bundler's interop handle it, or publish proper CJS by setting module to `commonjs`
- For object-shape exports, prefer named exports: `export const a = ...; export const b = ...;` instead of assigning one bag object
Example fix
// before
function createServer() { ... }
export = createServer;
// after
function createServer() { ... }
export default createServer; Defensive patterns
Strategy: validation
Validate before calling
// Detect export-assignment before ESM transform
function hasExportAssignment(src: string): boolean {
return /^\s*export\s*=\s*[^=]/m.test(src);
}
const moduleIsEsm = transformOptions.module === 'esm';
if (moduleIsEsm && hasExportAssignment(src)) {
throw new Error('export = cannot be emitted as ESM; use export default');
} Type guard
// Repo policy guard: fail CI on any CJS-style export syntax in ESM packages
function assertNoCjsExports(files: string[]) {
for (const f of files.filter(f => f.endsWith('.ts'))) {
if (/^\s*export\s*=/m.test(read(f))) throw new Error(`${f}: use export default / named exports`);
}
} Try / catch
// Gate on the TS code after transform, mirroring tsc
for (const d of result.errors) {
if (d.code === 'TS1203') queueForEsmRewrite(d.file, d.span);
} Prevention
- Adopt `export default` / named exports in all files destined for ESM output
- When absorbing legacy packages, convert `export =` in the same commit that switches the build to ESM
- Run tsc with `module: esnext` over the source as a cross-check; TS1203 there catches the same mismatch early
When it happens
Trigger: Configuring oxc-transform with `module: Esm` and transforming a TypeScript file containing `export = someObjectOrFunction;` (enter_statement → transform_ts_export_assignment at module.rs:42-46). The statement is still lowered to `module.exports = ...`, so the emitted ESM file would call a nonexistent `module` binding unless a bundler cleans it up.
Common situations: Legacy `.d.ts`-adjacent implementation files and old Node library code written with `export =` for exact CJS shape control, later fed into an ESM-first build (Vite/Rollup-style config with oxc); migrating packages from `module: commonjs` tsconfig to ESM without rewriting export style; generated code from older OpenAPI/gRPC toolchains that emits `export =` clients.
Related errors
- TS1202
- Expected "import" statement instead of "require" call
- Ambient modules cannot be nested in other modules or namespa
- Namespaces exporting non-const are not supported by Oxc. Cha
- Namespace not marked type-only declare are disabled. To enab
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/7a3a41bea7cdfd12.
Report an issue: GitHub.