facebook/flow · error
Records cannot have private methods
Error message
Records cannot have private methods
What it means
When lowering record body elements, a method keyed by Key::PrivateName (a #name member) hits an unconditional panic: records do not support private members. The typer has no representation for record-private methods, so this is a hard error in the typing pass.
Source
Thrown at rust_port/crates/flow_typing_statement/src/statement.rs:18895
false,
Name::new(name),
method_id_loc,
Some(func_loc),
static_
&& flow_parser_utils::this_finder::function_uses_this(
func,
),
method_sig,
Some(set_asts),
Some(set_type),
&mut class_sig,
);
rev_elements.push(Box::new(get_element));
}
}
}
expression::object::Key::PrivateName(_) => {
panic!("Records cannot have private methods")
}
expression::object::Key::StringLiteral(_)
| expression::object::Key::NumberLiteral(_)
| expression::object::Key::BigIntLiteral(_)
| expression::object::Key::Computed(_) => {
panic!("Records can only have identifier method keys")
}
},
statement::record_declaration::BodyElement::Property(prop) => {
let statement::record_declaration::Property {
loc: prop_loc,
key,
annot,
default_value,
comments: prop_comments,
invalid_syntax: _,
} = prop;View on GitHub (pinned to 5c86586199)
Solutions
- Remove the #private member from the record body.
- Move the helper out as a module-level function that takes the record as a parameter.
- Use a class if private state is essential to the design.
- Codemods: rewrite private members into free functions when emitting records.
Example fix
// before
record Counter {
value: number;
#reset() { }
}
// after: no private members; move the logic out
record Counter { value: number; }
function reset(c: Counter): Counter { return { value: 0 }; } Defensive patterns
Strategy: validation
Validate before calling
// lint before typechecking: records must not contain private members
function recordHasPrivateMember(node) {
return node.body.some(
(el) => (el.type === 'Method' || el.type === 'Property') && el.key?.type === 'PrivateName'
);
}
if (recordHasPrivateMember(recordNode)) reportError(recordNode, 'records cannot have private members'); Type guard
function recordMemberAllowed(el) {
if (el.type === 'Property') return el.key.type === 'Identifier';
if (el.type !== 'Method') return false;
return el.kind === 'method' && el.key.type === 'Identifier';
} Prevention
- Move private helpers out of records into module-level functions taking the record.
- Use classes when private state is part of the design.
- Extend the record lint rule to reject PrivateName keys of any member kind.
- Check codemod output for #members when converting encapsulated classes.
When it happens
Trigger: Typechecking a record whose body declares a #private field or method — record Counter { value: number; #reset() { ... } } — after the parser accepted the private-name key.
Common situations: Encapsulated-class patterns carried over into records; codemods preserving private helpers when converting classes; developers expecting class-private semantics inside records.
Related errors
- Records cannot have constructors
- Records cannot have getters
- Records cannot have setters
- 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/4fc8a6e3aafce605.
Report an issue: GitHub.