Skip to content

Commit c9eea9c

Browse files
committed
Fix props as union types
1 parent e1f4d41 commit c9eea9c

File tree

3 files changed

+114
-6
lines changed

3 files changed

+114
-6
lines changed

src/parser.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,16 @@ export function parseFromProgram(
303303
if (currentTypeNode === undefined) {
304304
currentTypeNode = propNode;
305305
} else if (currentTypeNode.$$id !== propNode.$$id) {
306+
let mergedPropType = t.unionNode([currentTypeNode.propType, propNode.propType]);
307+
306308
currentTypeNode = t.propNode(
307309
currentTypeNode.name,
308310
{
309311
description: currentTypeNode.description,
310312
defaultValue: currentTypeNode.defaultValue,
311313
visibility: currentTypeNode.visibility,
312314
},
313-
t.unionNode([currentTypeNode.propType, propNode.propType]),
315+
mergedPropType.types.length === 1 ? mergedPropType.types[0] : mergedPropType,
314316
currentTypeNode.optional || propNode.optional,
315317
new Set(Array.from(currentTypeNode.filenames).concat(Array.from(propNode.filenames))),
316318
undefined,
@@ -349,10 +351,18 @@ export function parseFromProgram(
349351
}
350352

351353
function parseComponentProps(name: string, type: ts.Type, sourceFile: ts.SourceFile | undefined) {
352-
const properties = type
353-
.getProperties()
354-
.filter((symbol) => shouldInclude({ name: symbol.getName(), depth: 1 }));
355-
if (properties.length === 0) {
354+
let allProperties: ts.Symbol[];
355+
if (type.isUnion()) {
356+
allProperties = type.types.flatMap((x) => x.getProperties());
357+
} else {
358+
allProperties = type.getProperties();
359+
}
360+
361+
const filteredProperties = allProperties.filter((symbol) =>
362+
shouldInclude({ name: symbol.getName(), depth: 1 }),
363+
);
364+
365+
if (filteredProperties.length === 0) {
356366
return;
357367
}
358368

@@ -361,7 +371,7 @@ export function parseFromProgram(
361371
programNode.body.push(
362372
t.componentNode(
363373
name,
364-
properties.map((x) => checkSymbol(x, new Set([(type as any).id]))),
374+
filteredProperties.map((x) => checkSymbol(x, new Set([(type as any).id]))),
365375
getDocumentation(checker.getSymbolAtLocation(type.symbol?.valueDeclaration!)),
366376
propsFilename,
367377
),

test/union-types/input.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as React from 'react';
2+
3+
function Component(props: PropsA | PropsB): React.ReactElement {
4+
return <div {...props} />;
5+
}
6+
7+
interface PropsA {
8+
matching: boolean;
9+
uniqueA: string;
10+
conflictingOptionality: string;
11+
conflictingType: string;
12+
}
13+
14+
interface PropsB {
15+
matching: boolean;
16+
uniqueB: string;
17+
conflictingOptionality?: string;
18+
conflictingType: number;
19+
}

test/union-types/output.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"nodeType": "program",
3+
"body": [
4+
{
5+
"nodeType": "component",
6+
"name": "Component",
7+
"props": [
8+
{
9+
"nodeType": "prop",
10+
"name": "matching",
11+
"propType": {
12+
"nodeType": "simpleType",
13+
"typeName": "boolean"
14+
},
15+
"optional": false,
16+
"filenames": {}
17+
},
18+
{
19+
"nodeType": "prop",
20+
"name": "uniqueA",
21+
"propType": {
22+
"nodeType": "simpleType",
23+
"typeName": "string"
24+
},
25+
"optional": false,
26+
"filenames": {}
27+
},
28+
{
29+
"nodeType": "prop",
30+
"name": "conflictingOptionality",
31+
"propType": {
32+
"nodeType": "union",
33+
"types": [
34+
{
35+
"nodeType": "simpleType",
36+
"typeName": "string"
37+
},
38+
{
39+
"nodeType": "simpleType",
40+
"typeName": "undefined"
41+
}
42+
]
43+
},
44+
"optional": true,
45+
"filenames": {}
46+
},
47+
{
48+
"nodeType": "prop",
49+
"name": "conflictingType",
50+
"propType": {
51+
"nodeType": "union",
52+
"types": [
53+
{
54+
"nodeType": "simpleType",
55+
"typeName": "string"
56+
},
57+
{
58+
"nodeType": "simpleType",
59+
"typeName": "number"
60+
}
61+
]
62+
},
63+
"optional": false,
64+
"filenames": {}
65+
},
66+
{
67+
"nodeType": "prop",
68+
"name": "uniqueB",
69+
"propType": {
70+
"nodeType": "simpleType",
71+
"typeName": "string"
72+
},
73+
"optional": false,
74+
"filenames": {}
75+
}
76+
]
77+
}
78+
]
79+
}

0 commit comments

Comments
 (0)