facebook/flow · error

Records cannot have constructors

Error message

Records cannot have constructors

What it means

Flow's record declarations are data-only: a record body may contain properties and plain methods, but the typing pass panics unconditionally on MethodKind::Constructor. Records have no instance construction path (they are created as object literals), so a constructor is not a recoverable diagnostic but a hard crash in the statement typing code.

Source

Thrown at rust_port/crates/flow_typing_statement/src/statement.rs:18857

                                                    loc: (method_id_loc_c, func_t),
                                                    name: method_id_clone.name.dupe(),
                                                    comments: method_id_clone.comments.dupe(),
                                                }),
                                            ),
                                            value: (func_loc_c, typed_func),
                                            kind: kind_c,
                                            static_: static_c,
                                            override_: false,
                                            ts_accessibility: None,
                                            decorators: vec![].into(),
                                            comments: method_comments_c,
                                        },
                                    ))
                                };

                                match kind {
                                    ast::class::MethodKind::Constructor => {
                                        panic!("Records cannot have constructors")
                                    }
                                    ast::class::MethodKind::Get => {
                                        panic!("Records cannot have getters")
                                    }
                                    ast::class::MethodKind::Set => {
                                        panic!("Records cannot have setters")
                                    }
                                    ast::class::MethodKind::Method => {
                                        check_duplicate_name(
                                            &mut public_seen_names,
                                            method_id_loc.dupe(),
                                            &Name::new(name.dupe()),
                                            static_,
                                            false,
                                            ClassMemberKind::ClassMemberMethod,
                                        );
                                        class_sig::add_method(
                                            static_,

View on GitHub (pinned to 5c86586199)

Solutions

  1. Delete the constructor from the record body.
  2. If you need validation or initialization, write a factory function that returns a record-typed object literal.
  3. If real construction logic is required, use a class instead of a record.
  4. Codemods: filter out constructor members when emitting record declarations.

Example fix

// before
record Point {
  constructor(x: number) { }
  x: number;
}

// after: records are data-only; use a factory
record Point { x: number; }
function makePoint(x: number): Point { return { x }; }
Defensive patterns

Strategy: validation

Validate before calling

// lint before typechecking: records must not contain constructors
function recordHasConstructor(node) {
  return node.body.some(
    (el) => el.type === 'Method' && el.kind === 'constructor'
  );
}
if (recordHasConstructor(recordNode)) reportError(recordNode, 'records cannot have constructors');

Type guard

function recordMemberAllowed(el) {
  if (el.type === 'Property') return true;
  if (el.type !== 'Method') return false;
  return el.kind === 'method' && el.key.type === 'Identifier';
}
const recordBodyOk = (rec) => rec.body.every(recordMemberAllowed);

Prevention

When it happens

Trigger: Typechecking a record declaration whose body contains a constructor method — e.g. record Point { constructor(x: number) {} x: number; } — in code where the parser admitted the member and typing reaches the record body lowering.

Common situations: Developers porting classes to records and keeping the constructor; codemods converting class-to-record mechanically; parser/typer version skew where the parser fails to reject the member before typing.

Related errors


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