{"record":{"id":"d49167f2b75b1aab","repo":"facebook/flow","slug":"records-cannot-have-constructors","errorCode":null,"errorMessage":"Records cannot have constructors","messagePattern":"Records cannot have constructors","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_typing_statement/src/statement.rs","lineNumber":18857,"sourceCode":"                                                    loc: (method_id_loc_c, func_t),\n                                                    name: method_id_clone.name.dupe(),\n                                                    comments: method_id_clone.comments.dupe(),\n                                                }),\n                                            ),\n                                            value: (func_loc_c, typed_func),\n                                            kind: kind_c,\n                                            static_: static_c,\n                                            override_: false,\n                                            ts_accessibility: None,\n                                            decorators: vec![].into(),\n                                            comments: method_comments_c,\n                                        },\n                                    ))\n                                };\n\n                                match kind {\n                                    ast::class::MethodKind::Constructor => {\n                                        panic!(\"Records cannot have constructors\")\n                                    }\n                                    ast::class::MethodKind::Get => {\n                                        panic!(\"Records cannot have getters\")\n                                    }\n                                    ast::class::MethodKind::Set => {\n                                        panic!(\"Records cannot have setters\")\n                                    }\n                                    ast::class::MethodKind::Method => {\n                                        check_duplicate_name(\n                                            &mut public_seen_names,\n                                            method_id_loc.dupe(),\n                                            &Name::new(name.dupe()),\n                                            static_,\n                                            false,\n                                            ClassMemberKind::ClassMemberMethod,\n                                        );\n                                        class_sig::add_method(\n                                            static_,","sourceCodeStart":18839,"sourceCodeEnd":18875,"githubUrl":"https://github.com/facebook/flow/blob/5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9/rust_port/crates/flow_typing_statement/src/statement.rs#L18839-L18875","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nrecord Point {\n  constructor(x: number) { }\n  x: number;\n}\n\n// after: records are data-only; use a factory\nrecord Point { x: number; }\nfunction makePoint(x: number): Point { return { x }; }","handlingStrategy":"validation","validationCode":"// lint before typechecking: records must not contain constructors\nfunction recordHasConstructor(node) {\n  return node.body.some(\n    (el) => el.type === 'Method' && el.kind === 'constructor'\n  );\n}\nif (recordHasConstructor(recordNode)) reportError(recordNode, 'records cannot have constructors');","typeGuard":"function recordMemberAllowed(el) {\n  if (el.type === 'Property') return true;\n  if (el.type !== 'Method') return false;\n  return el.kind === 'method' && el.key.type === 'Identifier';\n}\nconst recordBodyOk = (rec) => rec.body.every(recordMemberAllowed);","tryCatchPattern":null,"preventionTips":["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."],"tags":["flow","records","syntax","typing","class-members","constructor"],"backgroundTag":"flow-record-syntax-error","analyzedSha":"5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}