{"record":{"id":"27a1ecf59d9b9767","repo":"swc-project/swc","slug":"destructuring-pattern-inside-tsparameterproperty","errorCode":null,"errorMessage":"destructuring pattern inside TsParameterProperty","messagePattern":"destructuring pattern inside TsParameterProperty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_ecma_transforms_typescript/src/transform.rs","lineNumber":266,"sourceCode":"                    let (pat, expr, id) = match param {\n                        TsParamPropParam::Ident(binding_ident) => {\n                            let id = binding_ident.to_id();\n                            let prop_name = PropName::Ident(IdentName::from(&*binding_ident));\n                            let mut value_ident = Ident::from(&*binding_ident);\n                            value_ident.optional = false;\n                            let value = value_ident.into();\n\n                            (\n                                binding_ident.clone().into(),\n                                assign_value_to_this_prop(prop_name, value),\n                                id,\n                            )\n                        }\n                        TsParamPropParam::Assign(assign_pat) => {\n                            let AssignPat { left, .. } = &assign_pat;\n\n                            let Pat::Ident(binding_ident) = &**left else {\n                                unreachable!(\"destructuring pattern inside TsParameterProperty\");\n                            };\n\n                            let id = binding_ident.id.to_id();\n                            let prop_name = PropName::Ident(binding_ident.id.clone().into());\n                            let mut value_ident = binding_ident.id.clone();\n                            value_ident.optional = false;\n                            let value = value_ident.into();\n\n                            (\n                                assign_pat.clone().into(),\n                                assign_value_to_this_prop(prop_name, value),\n                                id,\n                            )\n                        }\n                        #[cfg(swc_ast_unknown)]\n                        _ => panic!(\"unable to access unknown nodes\"),\n                    };\n","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_ecma_transforms_typescript/src/transform.rs#L248-L284","documentation":"The TypeScript strip transform lowers parameter properties (`constructor(private a)`) into field declarations plus `this.a = a` assignments. It only supports identifier parameters: a TsParamPropParam::Assign whose left side is not Pat::Ident — i.e. a binding pattern like `constructor(private [a, b] = pair)` — is rejected as `destructuring pattern inside TsParameterProperty`. TypeScript itself forbids binding patterns in parameter properties, so valid parsed TS never reaches this.","triggerScenarios":"A parameter property declared with an array/object binding pattern — invalid TypeScript that nonetheless exists in the AST because it was built programmatically, parsed with a lenient/foreign parser, or mutated by a transform before the TS strip pass.","commonSituations":"AST generators and codemods synthesizing TS classes; estree/babel ASTs converted into swc ASTs; downleveling pipelines that accept non-tsc-validated input.","solutions":["Fix the input: use identifier parameters and destructure inside the constructor body.","Validate TsParamPropParam shapes before running swc_ecma_transforms_typescript (see type guard).","Report to the tool that produced parameter properties with binding patterns."],"exampleFix":"// before: binding pattern in a parameter property (invalid TS)\nclass C {\n  constructor(private [a, b] = pair) {}\n}\n\n// after: identifier parameter property + destructuring in body\nclass C {\n  private a; private b;\n  constructor(pair = [1, 2]) { ([this.a, this.b] = pair); }\n}","handlingStrategy":"type-guard","validationCode":"use swc_ecma_ast::{Pat, TsParamPropParam};\nfn param_props_ok(p: &TsParamPropParam) -> bool {\n    match p {\n        TsParamPropParam::Ident(_) => true,\n        TsParamPropParam::Assign(a) => matches!(&*a.left, Pat::Ident(_)),\n    }\n}\n// run over every Constructor param before the TS strip transform","typeGuard":"fn is_supported_param_prop(p: &TsParamPropParam) -> bool {\n    match p {\n        TsParamPropParam::Ident(_) => true,\n        TsParamPropParam::Assign(a) => matches!(&*a.left, Pat::Ident(_)),\n    }\n}","tryCatchPattern":null,"preventionTips":["Never declare parameter properties with binding patterns — tsc rejects them too.","If you generate TS ASTs, keep constructor params as identifiers.","Run tsc --noEmit over generated TypeScript to catch invalid shapes before swc."],"tags":["swc","typescript","strip-types","parameter-properties","destructuring","invalid-syntax","panic"],"backgroundTag":"invalid-typescript-syntax","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}