oxc-project/oxc · warning

ES2015 module syntax is preferred over namespaces.

Error message

ES2015 module syntax is preferred over namespaces.

What it means

Diagnostic from oxlint's port of @typescript-eslint/no-namespace. Custom TypeScript namespaces (`namespace Foo {}`) predate ES2015 modules and produce runtime objects + harder tree-shaking, so the rule reports namespace declarations in normal code and recommends ES module syntax (or `declare module` for ambient typing). Options: `allowDeclarations` permits `declare namespace`, and definition files (.d.ts) can be exempted.

Source

Thrown at crates/oxc_linter/src/rules/typescript/no_namespace.rs:16

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use schemars::JsonSchema;
use serde::Deserialize;

use crate::{
    AstNode,
    context::{ContextHost, LintContext},
    rule::{DefaultRuleConfig, Rule},
    utils::has_ambient_typescript_ancestor,
};

fn no_namespace_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("ES2015 module syntax is preferred over namespaces.")
        .with_help("Replace the namespace with an ES2015 module or use `declare module`")
        .with_label(span)
}

#[derive(Debug, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoNamespace {
    /// Whether to allow declare with custom TypeScript namespaces.
    ///
    /// Examples of **incorrect** code for this rule when `{ "allowDeclarations": true }`
    /// ```typescript
    /// module foo {}
    /// namespace foo {}
    /// ```
    ///
    /// Examples of **correct** code for this rule when `{ "allowDeclarations": true }`
    /// ```typescript
    /// declare module 'foo' {}

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Convert the namespace to an ES module: move members to a file, `export` them, `import` at use sites.
  2. For pure typing, use ambient declarations: `declare module 'x'` or `declare namespace` with `"allowDeclarations": true`.
  3. Enable `"allowDefinitionFiles": true` if .d.ts files legitimately need namespaces.
  4. For a wrapped-value pattern (namespace as object literal), replace with a plain exported const object.

Example fix

// before: MathUtils.ts
namespace MathUtils {
  export const add = (a: number, b: number) => a + b;
}
// consumer: MathUtils.add(1, 2);

// after: MathUtils.ts
export const add = (a: number, b: number) => a + b;
// consumer: import { add } from './MathUtils'; add(1, 2);
Defensive patterns

Strategy: validation

Validate before calling

oxlint --ts-plugin src/ # no-namespace; allowDeclarations/allowDefinitionFiles per config

Prevention

When it happens

Trigger: A `namespace X { ... }` declaration in a non-declaration file (or a `declare namespace` when allowDeclarations is false). The rule consults `has_ambient_typescript_ancestor` to skip ambient contexts; module augmentation and `declare module 'name'` forms are the recommended alternatives per the help text.

Common situations: Legacy codebases from pre-ES2015-module days; namespace used as a bundling/organization device inside one file; global type pollution via namespaces; migrating internal modules to `import`/`export` during a modernization.

Related errors


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