facebook/flow · error

CommonJS exports cannot be combined with ES module exports.

Error message

CommonJS exports cannot be combined with ES module exports.

What it means

flowDefToTSDef throws this translationError when a Flow libdef module mixes CommonJS exports (declare module.exports) with ES-module-style export declarations (ExportAllDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, or DeclareExportDeclaration) in the same file. TypeScript cannot express both `export =` and ES export syntax for one module, so the translator refuses the input rather than emitting invalid TS.

Source

Thrown at packages/flow-api-translator/src/flowDefToTSDef.js:2007

      | [
          TSESTree.VariableDeclaration,
          TSESTree.TSTypeAliasDeclaration,
          TSESTree.TSExportAssignment,
        ] {
      // TS forbids `export = ` in a module that has any other export, so a
      // module combining the two has no faithful translation.
      if (
        node.parent.type === 'Program' &&
        node.parent.body.some(
          statement =>
            statement.type === 'DeclareExportAllDeclaration' ||
            statement.type === 'DeclareExportDeclaration' ||
            statement.type === 'ExportAllDeclaration' ||
            statement.type === 'ExportDefaultDeclaration' ||
            statement.type === 'ExportNamedDeclaration',
        )
      ) {
        throw translationError(
          node,
          'CommonJS exports cannot be combined with ES module exports.',
        );
      }

      // `declare module.exports: T` is TS's `export = <value>`, which - like
      // `export default` - can only name a value.
      const type = node.typeAnnotation.typeAnnotation;

      if (
        type.type === 'TypeofTypeAnnotation' &&
        type.argument.type === 'Identifier' &&
        isDeclaredClass(type.argument.name)
      ) {
        return {
          type: 'TSExportAssignment',
          loc: DUMMY_LOC,
          expression: {

View on GitHub (pinned to 5c86586199)

Solutions

  1. Remove one export style from the libdef: if it uses `declare module.exports`, delete the ES export declarations (and vice versa).
  2. Migrate the whole file to ES module syntax: replace `declare module.exports: T` with `declare export default T` or named `declare export` statements.
  3. Split the module into two files if some exports are genuinely CommonJS and others ES-style.
  4. Re-run the translator after fixing to confirm the libdef converts cleanly.

Example fix

// before (libdef)
declare module.exports: number;
declare export foo(): void;
// after
declare export default number;
declare export foo(): void;
Defensive patterns

Strategy: validation

Validate before calling

function hasMixedExports(body) {
  const cjs = body.some(s => s.type === 'DeclareModuleExports');
  const es = body.some(s =>
    ['DeclareExportDeclaration', 'ExportAllDeclaration', 'ExportDefaultDeclaration', 'ExportNamedDeclaration'].includes(s.type));
  return cjs && es; // true => translator will throw; fix the file first
}

Type guard

function isPureEsModule(body) {
  return !body.some(s => s.type === 'DeclareModuleExports');
}

Try / catch

try {
  const tsDef = flowDefToTSDef(ast);
} catch (e) {
  if (String(e.message).includes('CommonJS exports cannot be combined')) {
    console.error('Libdef mixes module.exports with ES exports; rewrite as pure ES module.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Running flowDefToTSDef on a Flow libdef file whose top-level statement list contains both a `declare module.exports` statement and any ES-style export declaration node.

Common situations: Hand-edited or auto-merged libdefs that combined legacy `declare module.exports: T` CommonJS form with modern `declare export ...` statements; converting old libdefs to the newer ES syntax and leaving both forms in place; copy-pasting export blocks between libdef files.

Related errors


AI-assisted analysis of facebook/flow@5c86586199 (2026-09-08). Data as JSON: /api/errors/d4bb0fb6333fdf5f. Report an issue: GitHub.