Skip to content

Commit e2ca96f

Browse files
committed
fix(transformer/typescript): parameter property assignments before conditional super()
When `super()` is inside a top-level control flow statement (if/else, switch, try, labeled), parameter property assignments were inserted at the start of the constructor body — before `super()`. Fixes #20527
1 parent 728fc8d commit e2ca96f

3 files changed

Lines changed: 87 additions & 11 deletions

File tree

  • crates/oxc_transformer/src/typescript
  • tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/class-constructor-arguments-conditional-super

crates/oxc_transformer/src/typescript/class.rs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -311,19 +311,43 @@ impl<'a> TypeScript<'a> {
311311
Self::create_assignment(target, value, ctx)
312312
}
313313

314-
/// Find the position of the `super()` call in the constructor body, otherwise return 0.
314+
/// Find the position after the `super()` call in the constructor body, otherwise return 0.
315315
///
316-
/// Don't need to handle nested `super()` call because `TypeScript` doesn't allow it.
316+
/// If `super()` is nested inside a top-level control flow statement, return the position after
317+
/// the containing statement.
317318
pub fn get_super_call_position(statements: &[Statement<'a>]) -> usize {
318-
// Find the position of the `super()` call in the constructor body.
319-
// Don't need to handle nested `super()` call because `TypeScript` doesn't allow it.
320-
statements
321-
.iter()
322-
.position(|stmt| {
323-
matches!(stmt, Statement::ExpressionStatement(stmt)
324-
if stmt.expression.is_super_call_expression())
325-
})
326-
.map_or(0, |pos| pos + 1)
319+
statements.iter().position(Self::statement_contains_super_call).map_or(0, |pos| pos + 1)
320+
}
321+
322+
fn statement_contains_super_call(stmt: &Statement<'a>) -> bool {
323+
match stmt {
324+
Statement::ExpressionStatement(stmt) => stmt.expression.is_super_call_expression(),
325+
Statement::BlockStatement(stmt) => {
326+
stmt.body.iter().any(Self::statement_contains_super_call)
327+
}
328+
Statement::IfStatement(stmt) => {
329+
Self::statement_contains_super_call(&stmt.consequent)
330+
|| stmt
331+
.alternate
332+
.as_ref()
333+
.is_some_and(|stmt| Self::statement_contains_super_call(stmt))
334+
}
335+
Statement::SwitchStatement(stmt) => stmt
336+
.cases
337+
.iter()
338+
.any(|case| case.consequent.iter().any(Self::statement_contains_super_call)),
339+
Statement::TryStatement(stmt) => {
340+
stmt.block.body.iter().any(Self::statement_contains_super_call)
341+
|| stmt.handler.as_ref().is_some_and(|handler| {
342+
handler.body.body.iter().any(Self::statement_contains_super_call)
343+
})
344+
|| stmt.finalizer.as_ref().is_some_and(|block| {
345+
block.body.iter().any(Self::statement_contains_super_call)
346+
})
347+
}
348+
Statement::LabeledStatement(stmt) => Self::statement_contains_super_call(&stmt.body),
349+
_ => false,
350+
}
327351
}
328352

329353
/// Convert computed key to sequence expression if there are assignments.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class MyError extends Error {
2+
constructor(
3+
public code: string,
4+
public description?: string,
5+
) {
6+
if (description) {
7+
super(code + ': ' + description);
8+
} else {
9+
super(code);
10+
}
11+
this.name = 'MyError';
12+
}
13+
}
14+
15+
class MyError2 extends Error {
16+
constructor(
17+
public code: string,
18+
) {
19+
switch (code) {
20+
case 'A':
21+
super('Error A');
22+
break;
23+
default:
24+
super(code);
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class MyError extends Error {
2+
constructor(code, description) {
3+
if (description) {
4+
super(code + ': ' + description);
5+
} else {
6+
super(code);
7+
}
8+
this.code = code;
9+
this.description = description;
10+
this.name = 'MyError';
11+
}
12+
}
13+
14+
class MyError2 extends Error {
15+
constructor(code) {
16+
switch (code) {
17+
case 'A':
18+
super('Error A');
19+
break;
20+
default:
21+
super(code);
22+
}
23+
this.code = code;
24+
}
25+
}

0 commit comments

Comments
 (0)