oxc-project/oxc · error · OxcDiagnostic
TS1202
TS1202
Error message
Import assignment cannot be used when targeting ECMAScript modules.
What it means
This is Oxc's port of TypeScript error TS1202: `import x = require("...")` (TSImportEqualsDeclaration with an ExternalModuleReference) is a CommonJS-style import assignment and cannot be emitted when the output module format is ECMAScript modules. The TypeScript module transform lowers it to `const x = require("...")` and reports the diagnostic when `self.module.is_esm()` at crates/oxc_transformer/src/typescript/module.rs:157-159. Note `Module::is_esm()` (options/module.rs:28) is true only for `Module::Esm`; the default `Module::Preserve` does not trigger it.
Source
Thrown at crates/oxc_transformer/src/typescript/diagnostics.rs:6
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 {View on GitHub (pinned to e1e7af627c)
Solutions
- Replace with ESM syntax: `import * as ns from "mod"`, `import { a } from "mod"`, or default-import `import d from "mod"` (the help text in diagnostics.rs lists exactly these)
- If the import exists only to defer/lazy-load, use dynamic import: `const mod = await import("mod")` or `import("mod").then(...)`
- If the file must stay CommonJS-style, set the transform's module option to `commonjs` so `module.is_esm()` is false (note: `Preserve`, the default, also does not error)
- For pure type aliases to modules, mark it type-only (`import type x = require('m')`) or ensure all references are types so it is removed instead of lowered
Example fix
// before
import utils = require('./utils');
export = doThing(utils);
// after
import * as utils from './utils';
export default doThing(utils); Defensive patterns
Strategy: validation
Validate before calling
// Before running the ESM-output transform, detect import-equals in sources
function hasImportEquals(src: string): boolean {
return /^\s*(export\s+)?import\s+\w+\s*=\s*require\s*\(/m.test(src);
}
// Grounded decision: only warn when output module is Esm
const moduleIsEsm = transformOptions.module === 'esm';
if (moduleIsEsm && hasImportEquals(src)) failBuild('rewrite import x = require(...)'); Type guard
// Static guard for a TS codebase: ban the syntax via config instead of runtime
tsconfig: { "module": "esnext", "verbatimModuleSyntax": true } // makes tsc flag import = for ESM Try / catch
// oxc collects diagnostics rather than throwing; gate your pipeline on the TS code
let result = transformer.build(source);
result.errors.iter().filter(|d| d.code() == Some(("TS", "1202"))).for_each(|d| {
route_to_esm_migration_todo(d);
}); Prevention
- Decide one module format per package and forbid the other's syntax via lint rules (`no-require-imports`, `@typescript-eslint/consistent-type-imports`)
- When migrating CJS-style TS to ESM, run a codemod converting `import x = require('m')` to `import` forms before flipping the module option
- Keep the transform's module option explicit (`esm` or `commonjs`) instead of relying on defaults so this class of mismatch surfaces deterministically
- For type-only module aliases use `import type` so they are stripped rather than lowered to require()
When it happens
Trigger: Configuring oxc-transform with `module: Esm` (or a Babel config mapping to ESM output) and transforming TypeScript containing `import fs = require('node:fs');` where the import has value references (type-only usages are stripped earlier). Both classic `import x = require('m')` forms and re-exported ones (`export import x = require('m')` reaches the same path via enter_declaration) can trip it.
Common situations: Migrating a legacy TS codebase (originally `module: commonjs`, full of `import x = require(...)` for cycles or lazy requires) to ESM output (`module: esnext`/`preserve`+ESM bundler); Node dual-mode packages where CJS-style TS is reused in an ESM build; copying wiring/ORM snippets written for old Electron or Vue 2 toolchains into an ESM-targeted oxc pipeline.
Related errors
- TS1203
- 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/90f4a9452c2c216c.
Report an issue: GitHub.