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
- Delete the constructor from the record body.
- If you need validation or initialization, write a factory function that returns a record-typed object literal.
- If real construction logic is required, use a class instead of a record.
- 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
- Enable a lint rule that restricts record bodies to properties and plain identifier-keyed methods.
- In class-to-record codemods, drop constructor members and emit a factory function instead.
- Document record restrictions next to the syntax's enablement flag so users learn the boundary early.
- Run the lint in CI before the typechecker ever sees the file.
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
- Records cannot have getters
- Records cannot have setters
- Records cannot have private methods
- Records can only have identifier method keys
- Unexpected function parameter ${param.type}
AI-assisted analysis of facebook/flow@5c86586199 (2026-08-20).
Data as JSON: /api/errors/d49167f2b75b1aab.
Report an issue: GitHub.