Skip to content

Commit 9588d9b

Browse files
authored
1 parent dd8ff69 commit 9588d9b

File tree

7 files changed

+492
-24
lines changed

7 files changed

+492
-24
lines changed

tsparser/src/parser/types/snapshots/encore_tsparser__parser__types__tests__resolve_types@basic.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ input_file: tsparser/src/parser/types/testdata/basic.ts
250250
),
251251
),
252252
optional: None,
253+
as_type: None,
253254
},
254255
),
255256
),
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
---
2+
source: tsparser/src/parser/types/tests.rs
3+
expression: result
4+
input_file: tsparser/src/parser/types/testdata/mapped_as.ts
5+
---
6+
{
7+
"Person": Interface(
8+
Interface {
9+
fields: [
10+
InterfaceField {
11+
name: String(
12+
"name",
13+
),
14+
optional: false,
15+
typ: Basic(
16+
String,
17+
),
18+
},
19+
InterfaceField {
20+
name: String(
21+
"age",
22+
),
23+
optional: false,
24+
typ: Basic(
25+
Number,
26+
),
27+
},
28+
InterfaceField {
29+
name: String(
30+
"kind",
31+
),
32+
optional: false,
33+
typ: Basic(
34+
String,
35+
),
36+
},
37+
],
38+
index: None,
39+
call: None,
40+
},
41+
),
42+
"RemoveKind": Generic(
43+
Mapped(
44+
Mapped {
45+
in_type: Generic(
46+
Keyof(
47+
Keyof(
48+
Generic(
49+
TypeParam(
50+
TypeParam {
51+
idx: 0,
52+
constraint: None,
53+
},
54+
),
55+
),
56+
),
57+
),
58+
),
59+
value_type: Generic(
60+
Index(
61+
Index {
62+
source: Generic(
63+
TypeParam(
64+
TypeParam {
65+
idx: 0,
66+
constraint: None,
67+
},
68+
),
69+
),
70+
index: Generic(
71+
MappedKeyType(
72+
MappedKeyType,
73+
),
74+
),
75+
},
76+
),
77+
),
78+
optional: None,
79+
as_type: Some(
80+
Generic(
81+
Conditional(
82+
Conditional {
83+
check_type: Generic(
84+
MappedKeyType(
85+
MappedKeyType,
86+
),
87+
),
88+
extends_type: Literal(
89+
String(
90+
"kind",
91+
),
92+
),
93+
true_type: Basic(
94+
Never,
95+
),
96+
false_type: Generic(
97+
MappedKeyType(
98+
MappedKeyType,
99+
),
100+
),
101+
},
102+
),
103+
),
104+
),
105+
},
106+
),
107+
),
108+
"PersonNoKind": Interface(
109+
Interface {
110+
fields: [
111+
InterfaceField {
112+
name: String(
113+
"name",
114+
),
115+
optional: false,
116+
typ: Basic(
117+
String,
118+
),
119+
},
120+
InterfaceField {
121+
name: String(
122+
"age",
123+
),
124+
optional: false,
125+
typ: Basic(
126+
Number,
127+
),
128+
},
129+
],
130+
index: None,
131+
call: None,
132+
},
133+
),
134+
"Identity": Generic(
135+
Mapped(
136+
Mapped {
137+
in_type: Generic(
138+
Keyof(
139+
Keyof(
140+
Generic(
141+
TypeParam(
142+
TypeParam {
143+
idx: 0,
144+
constraint: None,
145+
},
146+
),
147+
),
148+
),
149+
),
150+
),
151+
value_type: Generic(
152+
Index(
153+
Index {
154+
source: Generic(
155+
TypeParam(
156+
TypeParam {
157+
idx: 0,
158+
constraint: None,
159+
},
160+
),
161+
),
162+
index: Generic(
163+
MappedKeyType(
164+
MappedKeyType,
165+
),
166+
),
167+
},
168+
),
169+
),
170+
optional: None,
171+
as_type: Some(
172+
Generic(
173+
MappedKeyType(
174+
MappedKeyType,
175+
),
176+
),
177+
),
178+
},
179+
),
180+
),
181+
"IdentityPerson": Interface(
182+
Interface {
183+
fields: [
184+
InterfaceField {
185+
name: String(
186+
"name",
187+
),
188+
optional: false,
189+
typ: Basic(
190+
String,
191+
),
192+
},
193+
InterfaceField {
194+
name: String(
195+
"age",
196+
),
197+
optional: false,
198+
typ: Basic(
199+
Number,
200+
),
201+
},
202+
InterfaceField {
203+
name: String(
204+
"kind",
205+
),
206+
optional: false,
207+
typ: Basic(
208+
String,
209+
),
210+
},
211+
],
212+
index: None,
213+
call: None,
214+
},
215+
),
216+
"OnlyStrings": Generic(
217+
Mapped(
218+
Mapped {
219+
in_type: Generic(
220+
Keyof(
221+
Keyof(
222+
Generic(
223+
TypeParam(
224+
TypeParam {
225+
idx: 0,
226+
constraint: None,
227+
},
228+
),
229+
),
230+
),
231+
),
232+
),
233+
value_type: Generic(
234+
Index(
235+
Index {
236+
source: Generic(
237+
TypeParam(
238+
TypeParam {
239+
idx: 0,
240+
constraint: None,
241+
},
242+
),
243+
),
244+
index: Generic(
245+
MappedKeyType(
246+
MappedKeyType,
247+
),
248+
),
249+
},
250+
),
251+
),
252+
optional: None,
253+
as_type: Some(
254+
Generic(
255+
Conditional(
256+
Conditional {
257+
check_type: Generic(
258+
Index(
259+
Index {
260+
source: Generic(
261+
TypeParam(
262+
TypeParam {
263+
idx: 0,
264+
constraint: None,
265+
},
266+
),
267+
),
268+
index: Generic(
269+
MappedKeyType(
270+
MappedKeyType,
271+
),
272+
),
273+
},
274+
),
275+
),
276+
extends_type: Basic(
277+
String,
278+
),
279+
true_type: Generic(
280+
MappedKeyType(
281+
MappedKeyType,
282+
),
283+
),
284+
false_type: Basic(
285+
Never,
286+
),
287+
},
288+
),
289+
),
290+
),
291+
},
292+
),
293+
),
294+
"PersonStrings": Interface(
295+
Interface {
296+
fields: [
297+
InterfaceField {
298+
name: String(
299+
"name",
300+
),
301+
optional: false,
302+
typ: Basic(
303+
String,
304+
),
305+
},
306+
InterfaceField {
307+
name: String(
308+
"kind",
309+
),
310+
optional: false,
311+
typ: Basic(
312+
String,
313+
),
314+
},
315+
],
316+
index: None,
317+
call: None,
318+
},
319+
),
320+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Mapped types with 'as' clause for key remapping
2+
3+
export interface Person {
4+
name: string;
5+
age: number;
6+
kind: string;
7+
}
8+
9+
// Test 1: Filter out properties using never
10+
export type RemoveKind<T> = {
11+
[K in keyof T as K extends "kind" ? never : K]: T[K]
12+
}
13+
export type PersonNoKind = RemoveKind<Person>;
14+
15+
// Test 2: Identity mapping
16+
export type Identity<T> = {
17+
[K in keyof T as K]: T[K]
18+
}
19+
export type IdentityPerson = Identity<Person>;
20+
21+
// Test 3: Filter based on value type
22+
export type OnlyStrings<T> = {
23+
[K in keyof T as T[K] extends string ? K : never]: T[K]
24+
}
25+
export type PersonStrings = OnlyStrings<Person>;

tsparser/src/parser/types/typ.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -567,14 +567,21 @@ pub struct Mapped {
567567
/// Whether to force fields to be optional (Some(True)), to make them required (Some(False)),
568568
/// or to keep them as-is (None).
569569
pub optional: Option<bool>,
570-
// Indicates a remapping of the property name.
571-
// Must be evaluated using the property name in the evaluation context.
572-
// pub as_type: Option<Box<Type>>,
570+
571+
/// Indicates a remapping of the property name.
572+
/// Must be evaluated using the property name in the evaluation context.
573+
pub as_type: Option<Box<Type>>,
573574
}
574575

575576
impl Mapped {
576577
pub fn identical(&self, other: &Mapped) -> bool {
577-
self.in_type.identical(&other.in_type) && self.value_type.identical(&other.value_type)
578+
self.in_type.identical(&other.in_type)
579+
&& self.value_type.identical(&other.value_type)
580+
&& match (&self.as_type, &other.as_type) {
581+
(Some(a), Some(b)) => a.identical(b),
582+
(None, None) => true,
583+
_ => false,
584+
}
578585
}
579586
}
580587

0 commit comments

Comments
 (0)