swc-project/swc · error
TsParameterProperty should be removed by typescript::strip p
Error message
TsParameterProperty should be removed by typescript::strip pass
What it means
The shared compat helper (behind the handle-functions macro used by es2015+ passes) rewrites function-like nodes and expects constructor parameters to already be plain Params. TypeScript parameter properties (`constructor(private x: number)`) are removed by the typescript strip pass; if it has not run, ParamOrTsParamProp::TsParamProp reaches unreachable!().
Source
Thrown at crates/swc_ecma_compat_common/src/macros.rs:120
}
fn visit_mut_constructor(&mut self, f: &mut Constructor) {
if f.body.is_none() {
return;
}
#[cfg(debug_assertions)]
tracing::trace!("visit_mut_constructor(parmas.len() = {})", f.params.len());
f.visit_mut_children_with(self);
let mut params = f
.params
.take()
.into_iter()
.map(|pat| match pat {
ParamOrTsParamProp::Param(p) => p,
_ => unreachable!(
"TsParameterProperty should be removed by typescript::strip pass"
),
})
.collect();
let body = f.body.as_mut().unwrap();
let (params, stmts) = self.visit_mut_fn_like(&mut params, &mut body.stmts);
#[cfg(debug_assertions)]
tracing::trace!(
"visit_mut_constructor(parmas.len() = {}, after)",
params.len()
);
f.params = params.into_iter().map(ParamOrTsParamProp::Param).collect();
body.stmts = stmts;
}
};View on GitHub (pinned to 5176682b65)
Solutions
- Use the official pass ordering: run the TypeScript transforms (typescript::strip or the full target chain via swc core's build/TransformOptions) before any es compat pass
- If assembling passes manually, prepend swc_ecma_transforms_typescript::strip to the chain
- Remove parameter properties from the source: declare fields explicitly and assign them in the constructor
Example fix
// before
class Service {
constructor(private logger: Logger) {}
}
// after
class Service {
private logger: Logger;
constructor(logger: Logger) { this.logger = logger; }
} Defensive patterns
Strategy: validation
Validate before calling
// Detect TS constructor parameter properties before running raw compat passes
let param_prop = regex::Regex::new(
r#"constructor\s*\([^)]*\b(?:public|private|protected|readonly|override)\s+[A-Za-z_$]"#,
).unwrap();
if param_prop.is_match(&ts_source) {
return Err("run typescript::strip before es compat passes".into());
} Try / catch
if let Err(p) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| apply_compat(&mut program))) {
if panic_message(&p).contains("TsParameterProperty") {
// fix: prepend swc_ecma_transforms_typescript::strip to the chain and retry
} else { std::panic::resume_unwind(p); }
} Prevention
- Use swc's official preset ordering (typescript strip before es compat) instead of hand-built chains
- In manual chains, always prepend typescript::strip when input can be TypeScript
- Lint against parameter properties in code processed by partial pipelines
When it happens
Trigger: Running an individual es2015 compat pass (classes, arrow, computed-props, etc. — anything built on these macros) directly on TypeScript source using constructor parameter properties, without typescript::strip having run first.
Common situations: Custom transform pipelines that cherry-pick compat passes instead of using swc's preset ordering; plugins applied to raw .ts input; migrating hand-rolled pass chains to newer swc versions.
Related errors
- using declaration must be removed by previous pass
- Object rest pattern should be removed by es2018::object_rest
- destructuring pattern inside TsParameterProperty
- Duplicated element (${elements[j].key})
- Method visitTsType not implemented.
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/5f4dc4f8953d6c08.
Report an issue: GitHub.