Skip to content

Commit ef29ef6

Browse files
authoredJan 17, 2025··
fix(typescript): Collect usages in extend clauses of classes and interfaces (#9893)
fixes #9875
1 parent aee2780 commit ef29ef6

File tree

10 files changed

+77
-40
lines changed

10 files changed

+77
-40
lines changed
 

‎.changeset/calm-pumpkins-explain.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
swc_typescript: patch
3+
---
4+
5+
fix(typescript): Collect usages in extend clauses of classes and interfaces

‎crates/swc_typescript/src/fast_dts/class.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,14 @@ use swc_ecma_ast::{
88

99
use super::{
1010
type_ann,
11-
util::ast_ext::{MemberExprExt, PatExt, PropNameExit},
11+
util::ast_ext::{ExprExit, PatExt, PropNameExit},
1212
FastDts,
1313
};
1414

1515
impl FastDts {
1616
pub(crate) fn transform_class(&mut self, class: &mut Class) {
1717
if let Some(super_class) = &class.super_class {
18-
let is_not_allowed = match super_class.as_ref() {
19-
Expr::Ident(_) => false,
20-
Expr::Member(member_expr) => !member_expr.get_first_object().is_ident(),
21-
_ => true,
22-
};
23-
18+
let is_not_allowed = super_class.get_root_ident().is_none();
2419
if is_not_allowed {
2520
self.extends_clause_expression(super_class.span());
2621
}

‎crates/swc_typescript/src/fast_dts/enum.rs

+10
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ impl FastDts {
126126
None
127127
}
128128
}
129+
Expr::OptChain(opt_chain) => {
130+
let member = opt_chain.base.as_member()?;
131+
let ident = member.obj.as_ident()?;
132+
if &ident.sym == enum_name {
133+
let name = member.prop.static_name()?;
134+
prev_members.get(name).cloned()
135+
} else {
136+
None
137+
}
138+
}
129139
_ => None,
130140
}
131141
}

‎crates/swc_typescript/src/fast_dts/types.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::{
1010
inferrer::ReturnTypeInferrer,
1111
type_ann,
1212
util::{
13-
ast_ext::{MemberExprExt, PatExt},
13+
ast_ext::{ExprExit, PatExt},
1414
types::{ts_keyword_type, ts_lit_type},
1515
},
1616
FastDts,
@@ -351,8 +351,7 @@ impl FastDts {
351351
}
352352

353353
let is_not_allowed = match key {
354-
Expr::Ident(_) => false,
355-
Expr::Member(member) => !member.get_first_object().is_ident(),
354+
Expr::Ident(_) | Expr::Member(_) | Expr::OptChain(_) => key.get_root_ident().is_none(),
356355
_ => !Self::is_literal(key),
357356
};
358357

‎crates/swc_typescript/src/fast_dts/util/ast_ext.rs

+19-27
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@ use std::borrow::Cow;
22

33
use swc_atoms::Atom;
44
use swc_ecma_ast::{
5-
BindingIdent, Expr, Lit, MemberExpr, MemberProp, ObjectPatProp, Pat, PropName, TsTypeAnn,
5+
BindingIdent, Expr, Ident, Lit, MemberProp, ObjectPatProp, Pat, PropName, TsTypeAnn,
66
};
77

8+
pub trait ExprExit {
9+
fn get_root_ident(&self) -> Option<&Ident>;
10+
}
11+
12+
impl ExprExit for Expr {
13+
fn get_root_ident(&self) -> Option<&Ident> {
14+
match self {
15+
Expr::Member(member_expr) => member_expr.obj.get_root_ident(),
16+
Expr::Ident(ident) => Some(ident),
17+
Expr::OptChain(opt_chain_expr) => opt_chain_expr
18+
.base
19+
.as_member()
20+
.and_then(|member_expr| member_expr.obj.get_root_ident()),
21+
_ => None,
22+
}
23+
}
24+
}
25+
826
pub trait PatExt {
927
fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>>;
1028
fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>);
@@ -119,29 +137,3 @@ impl MemberPropExt for MemberProp {
119137
}
120138
}
121139
}
122-
123-
pub trait MemberExprExt {
124-
fn get_first_object(&self) -> &Expr;
125-
}
126-
127-
impl MemberExprExt for MemberExpr {
128-
fn get_first_object(&self) -> &Expr {
129-
let mut object = &self.obj;
130-
loop {
131-
match object.as_ref() {
132-
Expr::Member(member_expr) => {
133-
object = &member_expr.obj;
134-
continue;
135-
}
136-
Expr::OptChain(opt_chain) => {
137-
if let Some(member_expr) = opt_chain.base.as_member() {
138-
object = &member_expr.obj;
139-
continue;
140-
}
141-
}
142-
_ => {}
143-
}
144-
break object;
145-
}
146-
}
147-
}

‎crates/swc_typescript/src/fast_dts/visitors/type_usage.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use swc_ecma_ast::{
1212
};
1313
use swc_ecma_visit::{Visit, VisitWith};
1414

15+
use crate::fast_dts::util::ast_ext::ExprExit;
16+
1517
pub struct TypeUsageAnalyzer<'a> {
1618
graph: DiGraph<Id, ()>,
1719
nodes: FxHashMap<Id, NodeIndex>,
@@ -99,14 +101,14 @@ impl TypeUsageAnalyzer<'_> {
99101

100102
impl Visit for TypeUsageAnalyzer<'_> {
101103
fn visit_ts_property_signature(&mut self, node: &TsPropertySignature) {
102-
if let Some(ident) = node.key.as_ident() {
104+
if let Some(ident) = node.key.get_root_ident() {
103105
self.add_edge(ident.to_id(), true);
104106
}
105107
node.visit_children_with(self);
106108
}
107109

108110
fn visit_ts_expr_with_type_args(&mut self, node: &TsExprWithTypeArgs) {
109-
if let Some(ident) = node.expr.as_ident() {
111+
if let Some(ident) = node.expr.get_root_ident() {
110112
self.add_edge(ident.to_id(), true);
111113
}
112114
node.visit_children_with(self);
@@ -238,7 +240,7 @@ impl Visit for TypeUsageAnalyzer<'_> {
238240

239241
fn visit_class(&mut self, node: &Class) {
240242
if let Some(super_class) = &node.super_class {
241-
if let Some(ident) = super_class.as_ident() {
243+
if let Some(ident) = super_class.get_root_ident() {
242244
self.add_edge(ident.to_id(), true);
243245
}
244246
}

‎crates/swc_typescript/tests/fixture/signature-computed-property-name.snap

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export type B = {
88
["foo" as string]: number;
99
["bar" as string](a: number): string;
1010
};
11+
export type C = {
12+
[D?.b]: number;
13+
};
1114
1215
1316
==================== Errors ====================

‎crates/swc_typescript/tests/fixture/signature-computed-property-name.ts

+4
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ export type B = {
77
["foo" as string]: number;
88
["bar" as string](a: number): string;
99
};
10+
11+
export type C = {
12+
[D?.b]: number;
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
```==================== .D.TS ====================
2+
3+
import type * as Member from "some-path/my_module";
4+
export interface IMember extends Member.C<"SimpleEntity"> {
5+
}
6+
import type * as Ident from "some-path/my_module";
7+
export interface IIdent extends Ident {
8+
}
9+
import * as Paren from "some-path/my_module";
10+
export declare class CParen extends Paren {
11+
}
12+
import * as OptChain from "some-path/my_module";
13+
export declare class COptChain extends OptChain?.C<"SimpleEntity"> {
14+
}
15+
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type * as Member from "some-path/my_module";
2+
export interface IMember extends Member.C<"SimpleEntity"> {}
3+
4+
import type * as Ident from "some-path/my_module";
5+
export interface IIdent extends Ident {}
6+
7+
import * as Paren from "some-path/my_module";
8+
export class CParen extends Paren {}
9+
10+
import * as OptChain from "some-path/my_module";
11+
export class COptChain extends OptChain?.C<"SimpleEntity"> {}

0 commit comments

Comments
 (0)
Please sign in to comment.