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

  1. Replace `export = expr` with `export default expr` (the diagnostic's own help text)
  2. 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`
  3. 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

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


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/7a3a41bea7cdfd12. Report an issue: GitHub.