facebook/flow · error · Error

Unexpected function parameter

Error message

Unexpected function parameter ${param.type}

What it means

Thrown by flow-api-translator while converting TypeScript definitions to Flow definitions (TSDefToFlowDef.js). _partitionAndTranslateTSFunctionParams only maps function parameters that are Identifier, ArrayPattern, or ObjectPattern nodes (plus a leading `this` Identifier and a trailing RestElement). Any other ESTree parameter node type hits the bare `throw new Error`, which bypasses the recoverFromErrors machinery used elsewhere in the file.

Solutions

  1. Rewrite the offending declaration to use an optional parameter instead of a default value, e.g. `declare function f(a?: number): void` instead of `declare function f(a = 1): void`.
  2. Locate the param by searching your d.ts for `=` inside parameter lists of declare function/interface/constructor signatures and remove those defaults.
  3. Wrap the translate call in try/catch per-file and skip/report files that use unsupported parameter forms.
  4. File an issue on flowlint/flow repo with the repro d.ts so the param type gets an explicit unsupportedFeature recovery path instead of a raw throw.

Example fix

// before (input .d.ts)
declare function connect(endpoint: string, retries = 3): void;

// after
ndeclare function connect(endpoint: string, retries?: number): void;
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-scan d.ts source for default-initialized params before translating
function hasUnsupportedFnParams(tsSource) {
  // AssignmentPattern = '=' default value inside a declare signature's param list
  return /(?:function\s+\w+|interface\s+\w+[\s\S]*?)[<(][^()=]*=\s*[^,)>]/.test(tsSource);
}

Type guard

const SUPPORTED_PARAMS = new Set(['Identifier', 'ArrayPattern', 'ObjectPattern', 'RestElement']);
function paramsAreSupported(fnLikeNode) {
  return fnLikeNode.params.every((p) => SUPPORTED_PARAMS.has(p.type));
}

Try / catch

try {
  const result = await unstable_translateTSDefToFlowDef({code: dts, recoverFromErrors: true});
} catch (e) {
  if (/^Unexpected function parameter/.test(e.message)) {
    reportFile(file, 'unsupported param form (default value / parameter property) — rewrite as optional param');
    continue; // skip file, keep batch running
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling unstable_translateTSDefToFlowDef on .d.ts code containing function/method signature parameters the translator does not model, e.g. `declare function f(a = 1): void` (AssignmentPattern), constructor parameter properties, or decorators on parameters. Only three param shapes are handled: Identifier, ArrayPattern, ObjectPattern.

Common situations: Converting real-world .d.ts files that use default-initialized parameters in declarations; TS interface method signatures with unusual param nodes; running codemods over large declaration bundles where one unhandled param aborts the whole translation.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/0f695d497dcff05c. Report an issue: GitHub.

Appendix: source

Thrown at packages/flow-api-translator/src/TSDefToFlowDef.js:1023

          } else if (
            param.type === 'ArrayPattern' ||
            param.type === 'ObjectPattern'
          ) {
            return constructFlowNode<FlowESTree.FunctionTypeParam>({
              type: 'FunctionTypeParam',
              name: constructFlowNode<FlowESTree.Identifier>({
                type: 'Identifier',
                name: `$$param${i}$`,
                optional: false,
                typeAnnotation: null,
              }),
              optional: Boolean(param.optional),
              typeAnnotation: Transform.TSTypeAnnotationOpt(
                param.typeAnnotation?.typeAnnotation,
              ),
            });
          } else {
            throw new Error(`Unexpected function parameter ${param.type}`);
          }
        }),
      };
    }

    static TSImportType(
      node: TSESTree.TSImportType,
    ): FlowESTree.TypeAnnotationType {
      const source =
        node.argument ??
        (node.source == null
          ? null
          : ({
              type: 'TSLiteralType',
              loc: node.source.loc,
              literal: node.source,
            } as TSESTree.TSLiteralType));
      if (source == null) {

View on GitHub (pinned to f88ac94bcf)