Skip to content

Commit 637d155

Browse files
sapphi-redclaude
andcommitted
feat(parser): add TS1174 error for classes extending multiple base classes
Implement TypeScript error TS1174 which is emitted when a class attempts to extend multiple base classes using comma-separated syntax (e.g., 'class C extends A, B { }'). In TypeScript, classes can only extend a single class, unlike interfaces which can extend multiple interfaces. This implementation: - Adds the diagnostic message with helpful guidance to use interfaces for multiple inheritance - Checks the extends clause after parsing to detect multiple base classes - Emits an error for each additional base class beyond the first Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent f317b33 commit 637d155

File tree

3 files changed

+69
-7
lines changed

3 files changed

+69
-7
lines changed

crates/oxc_parser/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,14 @@ pub fn extends_clause_must_precede_implements(span: Span, implements_span: Span)
327327
.with_help("Move the 'extends' clause before the 'implements' clause")
328328
}
329329

330+
// Classes can only extend a single class. ts(1174)
331+
#[cold]
332+
pub fn classes_can_only_extend_single_class(span: Span) -> OxcDiagnostic {
333+
ts_error("1174", "Classes can only extend a single class.")
334+
.with_label(span)
335+
.with_help("Remove the extra base class or use interfaces for multiple inheritance")
336+
}
337+
330338
// 'implements' clause already seen. ts(1175)
331339
#[cold]
332340
pub fn implements_clause_already_seen(span: Span, seen_span: Span) -> OxcDiagnostic {

crates/oxc_parser/src/js/class.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ impl<'a> ParserImpl<'a> {
9090
let first_extends = extends.remove(0);
9191
super_class = Some(first_extends.0);
9292
super_type_parameters = first_extends.1;
93+
for (_, _, span) in extends {
94+
self.error(diagnostics::classes_can_only_extend_single_class(span));
95+
}
9396
}
9497
let body = self.parse_class_body();
9598

tasks/coverage/snapshots/parser_typescript.snap

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ commit: 669c25c0
33
parser_typescript Summary:
44
AST Parsed : 9821/9822 (99.99%)
55
Positive Passed: 9812/9822 (99.90%)
6-
Negative Passed: 1482/2547 (58.19%)
6+
Negative Passed: 1485/2547 (58.30%)
77
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration3.ts
88

99
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration4.ts
@@ -120,8 +120,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/classExtendi
120120

121121
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/classExtendsInterface_not.ts
122122

123-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/classExtendsMultipleBaseClasses.ts
124-
125123
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/classExtendsNull.ts
126124

127125
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/classExtendsNull2.ts
@@ -686,8 +684,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/multipleExpo
686684

687685
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/multipleExports.ts
688686

689-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/multipleInheritance.ts
690-
691687
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/multivar.ts
692688

693689
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/namespaceMergedWithImportAliasNoCrash.ts
@@ -1758,8 +1754,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
17581754

17591755
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration18.ts
17601756

1761-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration6.ts
1762-
17631757
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration7.ts
17641758

17651759
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName4.ts
@@ -3628,6 +3622,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
36283622
4 │ }
36293623
╰────
36303624

3625+
× TS(1174): Classes can only extend a single class.
3626+
╭─[typescript/tests/cases/compiler/classExtendsMultipleBaseClasses.ts:3:19]
3627+
2 │ class B { }
3628+
3 │ class C extends A,B { }
3629+
· ─
3630+
╰────
3631+
help: Remove the extra base class or use interfaces for multiple inheritance
3632+
36313633
× Expected `(` but found `}`
36323634
╭─[typescript/tests/cases/compiler/classFieldsBrokenConstructorEmitNoCrash1.ts:4:1]
36333635
3 │ constructor
@@ -3636,6 +3638,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
36363638
· ╰── `(` expected
36373639
╰────
36383640

3641+
× TS(1174): Classes can only extend a single class.
3642+
╭─[typescript/tests/cases/compiler/classHeritageWithTrailingSeparator.ts:2:20]
3643+
1 │ class C { foo: number }
3644+
2 │ ╭─▶ class D extends C, {
3645+
3 │ ╰─▶ }
3646+
╰────
3647+
help: Remove the extra base class or use interfaces for multiple inheritance
3648+
36393649
× Expected `{` but found `EOF`
36403650
╭─[typescript/tests/cases/compiler/classHeritageWithTrailingSeparator.ts:3:2]
36413651
2 │ class D extends C, {
@@ -8415,6 +8425,24 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
84158425
5 │ public private p4;
84168426
╰────
84178427

8428+
× TS(1174): Classes can only extend a single class.
8429+
╭─[typescript/tests/cases/compiler/multipleInheritance.ts:9:21]
8430+
8 │
8431+
9 │ class C extends B1, B2 { // duplicate member
8432+
· ──
8433+
10 │ }
8434+
╰────
8435+
help: Remove the extra base class or use interfaces for multiple inheritance
8436+
8437+
× TS(1174): Classes can only extend a single class.
8438+
╭─[typescript/tests/cases/compiler/multipleInheritance.ts:18:21]
8439+
17 │
8440+
18 │ class E extends D1, D2 { // nope, duplicate member
8441+
· ──
8442+
19 │ }
8443+
╰────
8444+
help: Remove the extra base class or use interfaces for multiple inheritance
8445+
84188446
× Identifier `x` has already been declared
84198447
╭─[typescript/tests/cases/compiler/nameCollisions.ts:2:9]
84208448
1 │ namespace T {
@@ -21142,6 +21170,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2114221170
╰────
2114321171
help: Merge the two 'implements' clauses into one by a ','
2114421172

21173+
× TS(1174): Classes can only extend a single class.
21174+
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration6.ts:1:20]
21175+
1 │ class C extends A, B {
21176+
· ─
21177+
2 │ }
21178+
╰────
21179+
help: Remove the extra base class or use interfaces for multiple inheritance
21180+
2114521181
× Constructor implementation is missing.
2114621182
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration8.ts:2:3]
2114721183
1 │ class C {
@@ -21439,6 +21475,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2143921475
2 │ }
2144021476
╰────
2144121477

21478+
× TS(1174): Classes can only extend a single class.
21479+
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause2.ts:1:20]
21480+
1 │ ╭─▶ class C extends A, {
21481+
2 │ ╰─▶ }
21482+
╰────
21483+
help: Remove the extra base class or use interfaces for multiple inheritance
21484+
2144221485
× Expected `{` but found `EOF`
2144321486
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause2.ts:2:2]
2144421487
1 │ class C extends A, {
@@ -21460,6 +21503,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2146021503
2 │ }
2146121504
╰────
2146221505

21506+
× TS(1174): Classes can only extend a single class.
21507+
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause5.ts:1:20]
21508+
1 │ class C extends A, implements B, {
21509+
· ──────────
21510+
2 │ }
21511+
╰────
21512+
help: Remove the extra base class or use interfaces for multiple inheritance
21513+
2146321514
× Expected `{` but found `Identifier`
2146421515
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ExtendsOrImplementsClauses/parserErrorRecovery_ExtendsOrImplementsClause5.ts:1:31]
2146521516
1 │ class C extends A, implements B, {

0 commit comments

Comments
 (0)