Skip to content

Commit 395f338

Browse files
imdreamrunnerdanez
andauthored
fix: Correctly handle ObjectTypeSpreadProperty in object type annotations (#593)
Co-authored-by: Daniel Tschinder <[email protected]>
1 parent 4fc5b21 commit 395f338

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`getFlowType handles ObjectTypeSpreadProperty 1`] = `
4+
Object {
5+
"name": "signature",
6+
"raw": "{| apple: string, banana: string, ...OtherFruits |}",
7+
"signature": Object {
8+
"properties": Array [
9+
Object {
10+
"key": "apple",
11+
"value": Object {
12+
"name": "string",
13+
"required": true,
14+
},
15+
},
16+
Object {
17+
"key": "banana",
18+
"value": Object {
19+
"name": "string",
20+
"required": true,
21+
},
22+
},
23+
Object {
24+
"key": "orange",
25+
"value": Object {
26+
"name": "string",
27+
"required": true,
28+
},
29+
},
30+
],
31+
},
32+
"type": "object",
33+
}
34+
`;
35+
36+
exports[`getFlowType handles ObjectTypeSpreadProperty from imported types 1`] = `
37+
Object {
38+
"name": "signature",
39+
"raw": "{| apple: string, banana: string, ...MyType |}",
40+
"signature": Object {
41+
"properties": Array [
42+
Object {
43+
"key": "apple",
44+
"value": Object {
45+
"name": "string",
46+
"required": true,
47+
},
48+
},
49+
Object {
50+
"key": "banana",
51+
"value": Object {
52+
"name": "string",
53+
"required": true,
54+
},
55+
},
56+
Object {
57+
"key": "a",
58+
"value": Object {
59+
"name": "string",
60+
"required": true,
61+
},
62+
},
63+
Object {
64+
"key": "b",
65+
"value": Object {
66+
"name": "notImported",
67+
"nullable": true,
68+
"required": true,
69+
},
70+
},
71+
],
72+
},
73+
"type": "object",
74+
}
75+
`;
76+
77+
exports[`getFlowType handles nested ObjectTypeSpreadProperty 1`] = `
78+
Object {
79+
"name": "signature",
80+
"raw": "{| apple: string, banana: string, ...BreakfastFruits |}",
81+
"signature": Object {
82+
"properties": Array [
83+
Object {
84+
"key": "apple",
85+
"value": Object {
86+
"name": "string",
87+
"required": true,
88+
},
89+
},
90+
Object {
91+
"key": "banana",
92+
"value": Object {
93+
"name": "string",
94+
"required": true,
95+
},
96+
},
97+
Object {
98+
"key": "mango",
99+
"value": Object {
100+
"name": "string",
101+
"required": true,
102+
},
103+
},
104+
Object {
105+
"key": "orange",
106+
"value": Object {
107+
"name": "string",
108+
"required": true,
109+
},
110+
},
111+
Object {
112+
"key": "lemon",
113+
"value": Object {
114+
"name": "string",
115+
"required": true,
116+
},
117+
},
118+
],
119+
},
120+
"type": "object",
121+
}
122+
`;

src/utils/__tests__/getFlowType-test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,4 +1269,44 @@ describe('getFlowType', () => {
12691269
raw: '{ subAction: SubAction }',
12701270
});
12711271
});
1272+
1273+
it('handles ObjectTypeSpreadProperty', () => {
1274+
const typePath = statement(`
1275+
var x: {| apple: string, banana: string, ...OtherFruits |} = 2;
1276+
type OtherFruits = { orange: string }
1277+
`)
1278+
.get('declarations', 0)
1279+
.get('id')
1280+
.get('typeAnnotation')
1281+
.get('typeAnnotation');
1282+
1283+
expect(getFlowType(typePath, null, noopImporter)).toMatchSnapshot();
1284+
});
1285+
1286+
it('handles ObjectTypeSpreadProperty from imported types', () => {
1287+
const typePath = statement(`
1288+
var x: {| apple: string, banana: string, ...MyType |} = 2;
1289+
import type { MyType } from 'MyType';
1290+
`)
1291+
.get('declarations', 0)
1292+
.get('id')
1293+
.get('typeAnnotation')
1294+
.get('typeAnnotation');
1295+
1296+
expect(getFlowType(typePath, null, mockImporter)).toMatchSnapshot();
1297+
});
1298+
1299+
it('handles nested ObjectTypeSpreadProperty', () => {
1300+
const typePath = statement(`
1301+
var x: {| apple: string, banana: string, ...BreakfastFruits |} = 2;
1302+
type BreakfastFruits = { mango: string, ...CitrusFruits };
1303+
type CitrusFruits = { orange: string, lemon: string };
1304+
`)
1305+
.get('declarations', 0)
1306+
.get('id')
1307+
.get('typeAnnotation')
1308+
.get('typeAnnotation');
1309+
1310+
expect(getFlowType(typePath, null, mockImporter)).toMatchSnapshot();
1311+
});
12721312
});

src/utils/getFlowType.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,20 @@ function handleObjectTypeAnnotation(
219219
importer,
220220
),
221221
});
222+
} else if (t.ObjectTypeSpreadProperty.check(param.node)) {
223+
let spreadObject = resolveToValue(param.get('argument'), importer);
224+
if (t.GenericTypeAnnotation.check(spreadObject.value)) {
225+
const typeAlias = resolveToValue(spreadObject.get('id'), importer);
226+
if (t.ObjectTypeAnnotation.check(typeAlias.get('right').value)) {
227+
spreadObject = resolveToValue(typeAlias.get('right'), importer);
228+
}
229+
}
230+
const props = handleObjectTypeAnnotation(
231+
spreadObject,
232+
typeParams,
233+
importer,
234+
) as ObjectSignatureType;
235+
type.signature.properties.push(...props.signature.properties);
222236
}
223237
});
224238

0 commit comments

Comments
 (0)