swc-project/swc · error
destructuring pattern inside TsParameterProperty
Error message
destructuring pattern inside TsParameterProperty
What it means
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.
Source
Thrown at crates/swc_ecma_transforms_typescript/src/transform.rs:266
let (pat, expr, id) = match param {
TsParamPropParam::Ident(binding_ident) => {
let id = binding_ident.to_id();
let prop_name = PropName::Ident(IdentName::from(&*binding_ident));
let mut value_ident = Ident::from(&*binding_ident);
value_ident.optional = false;
let value = value_ident.into();
(
binding_ident.clone().into(),
assign_value_to_this_prop(prop_name, value),
id,
)
}
TsParamPropParam::Assign(assign_pat) => {
let AssignPat { left, .. } = &assign_pat;
let Pat::Ident(binding_ident) = &**left else {
unreachable!("destructuring pattern inside TsParameterProperty");
};
let id = binding_ident.id.to_id();
let prop_name = PropName::Ident(binding_ident.id.clone().into());
let mut value_ident = binding_ident.id.clone();
value_ident.optional = false;
let value = value_ident.into();
(
assign_pat.clone().into(),
assign_value_to_this_prop(prop_name, value),
id,
)
}
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
};
View on GitHub (pinned to 5176682b65)
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.
Example fix
// before: binding pattern in a parameter property (invalid TS)
class C {
constructor(private [a, b] = pair) {}
}
// after: identifier parameter property + destructuring in body
class C {
private a; private b;
constructor(pair = [1, 2]) { ([this.a, this.b] = pair); }
} Defensive patterns
Strategy: type-guard
Validate before calling
use swc_ecma_ast::{Pat, TsParamPropParam};
fn param_props_ok(p: &TsParamPropParam) -> bool {
match p {
TsParamPropParam::Ident(_) => true,
TsParamPropParam::Assign(a) => matches!(&*a.left, Pat::Ident(_)),
}
}
// run over every Constructor param before the TS strip transform Type guard
fn is_supported_param_prop(p: &TsParamPropParam) -> bool {
match p {
TsParamPropParam::Ident(_) => true,
TsParamPropParam::Assign(a) => matches!(&*a.left, Pat::Ident(_)),
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: AST generators and codemods synthesizing TS classes; estree/babel ASTs converted into swc ASTs; downleveling pipelines that accept non-tsc-validated input.
Related errors
- {decl:?}
- Duplicated element (${elements[j].key})
- illegal conversion: Cannot convert {:?} to ModuleDeclaration
- illegal conversion: Cannot convert {:?} to PatOutput
- illegal conversion: Cannot convert {:?} to Pattern
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/27a1ecf59d9b9767.
Report an issue: GitHub.