Skip to content

Commit 7a46827

Browse files
✨ Adds support for React.FC & FC (#183)
* ✨ Adds support for React.FC & FC * docs(changeset): Adds support for React.FC and FC
1 parent 0b9456e commit 7a46827

File tree

5 files changed

+135
-11
lines changed

5 files changed

+135
-11
lines changed

.changeset/tough-crews-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'extract-react-types': patch
3+
---
4+
5+
Adds support for React.FC and FC

packages/extract-react-types/__snapshots__/converters-typescript.test.js.snap

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,69 @@ Object {
2828
}
2929
`;
3030

31+
exports[`TypeScript: FC 1`] = `
32+
Object {
33+
"kind": "generic",
34+
"name": Object {
35+
"kind": "id",
36+
"name": "Component",
37+
"type": null,
38+
},
39+
"value": Object {
40+
"kind": "object",
41+
"members": Array [
42+
Object {
43+
"key": Object {
44+
"kind": "id",
45+
"name": "children",
46+
},
47+
"kind": "property",
48+
"optional": false,
49+
"value": Object {
50+
"kind": "string",
51+
},
52+
},
53+
],
54+
"referenceIdName": "Props",
55+
},
56+
}
57+
`;
58+
59+
exports[`TypeScript: FC with empty type argument 1`] = `
60+
Object {
61+
"kind": "any",
62+
"name": Object {
63+
"kind": "id",
64+
"name": "Component",
65+
"type": null,
66+
},
67+
}
68+
`;
69+
70+
exports[`TypeScript: FC with inline type argument 1`] = `
71+
Object {
72+
"kind": "object",
73+
"members": Array [
74+
Object {
75+
"key": Object {
76+
"kind": "id",
77+
"name": "children",
78+
},
79+
"kind": "property",
80+
"optional": false,
81+
"value": Object {
82+
"kind": "string",
83+
},
84+
},
85+
],
86+
"name": Object {
87+
"kind": "id",
88+
"name": "Component",
89+
"type": null,
90+
},
91+
}
92+
`;
93+
3194
exports[`TypeScript: React.ComponentType 1`] = `
3295
Object {
3396
"kind": "generic",

packages/extract-react-types/converters-typescript.test.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const TESTS = [
6565
`
6666
},
6767
{
68-
name: 'React.FC',
68+
name: 'FC',
6969
typeSystem: 'typescript',
7070
code: `
7171
type Props = {
@@ -78,7 +78,7 @@ const TESTS = [
7878
`
7979
},
8080
{
81-
name: 'React.FC with empty type argument',
81+
name: 'FC with empty type argument',
8282
typeSystem: 'typescript',
8383
code: `
8484
type Props = {
@@ -91,7 +91,7 @@ const TESTS = [
9191
`
9292
},
9393
{
94-
name: 'React.FC with inline type argument',
94+
name: 'FC with inline type argument',
9595
typeSystem: 'typescript',
9696
code: `
9797
const Component: FC<{
@@ -101,6 +101,47 @@ const TESTS = [
101101
export default Component;
102102
`
103103
},
104+
{
105+
name: 'React.FC',
106+
typeSystem: 'typescript',
107+
code: `
108+
import React from 'react';
109+
110+
type Props = {
111+
children: string;
112+
};
113+
114+
const Component: React.FC<Props> = (props) => null;
115+
116+
export default Component;
117+
`
118+
},
119+
{
120+
name: 'React.FC with empty type argument',
121+
typeSystem: 'typescript',
122+
code: `
123+
import React from 'react';
124+
125+
type Props = {
126+
children: string;
127+
};
128+
129+
const Component: React.FC = (props) => null;
130+
131+
export default Component;
132+
`
133+
},
134+
{
135+
name: 'React.FC with inline type argument',
136+
typeSystem: 'typescript',
137+
code: `
138+
const Component: React.FC<{
139+
children: string;
140+
}> = (props) => null;
141+
142+
export default Component;
143+
`
144+
},
104145
{
105146
name: 'Direct type assignment',
106147
typeSystem: 'typescript',

packages/extract-react-types/src/converter.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
hasDestructuredDefaultExport,
1616
matchExported
1717
} from './export-manager';
18-
18+
import { hasTypeAnnotation } from './utils';
1919
import * as K from './kinds';
2020

2121
const converters = {};
@@ -1277,13 +1277,8 @@ export function convertComponentExports(componentExports, context) {
12771277
) {
12781278
let propType;
12791279

1280-
// check for a component typed with the `FC<Props>` annotation
1281-
if (
1282-
path.parentPath.node.id &&
1283-
path.parentPath.node.id.typeAnnotation &&
1284-
path.parentPath.node.id.typeAnnotation.typeAnnotation.typeName.name === 'FC' &&
1285-
path.parentPath.node.id.typeAnnotation.typeAnnotation.typeParameters
1286-
) {
1280+
// check for a component typed with the `React.FC<Props>` or `FC<Props>` type annotation
1281+
if (hasTypeAnnotation(path.parentPath, 'React', 'FC')) {
12871282
propType = path.parentPath.get('id.typeAnnotation.typeAnnotation.typeParameters.params.0');
12881283
} else {
12891284
// we have a normal function, assume the props are the first parameter
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* eslint-disable import/prefer-default-export */
2+
3+
export function hasTypeAnnotation(path, left, right) {
4+
if (!path.isVariableDeclarator() || !path.node.id.typeAnnotation) {
5+
return false;
6+
}
7+
8+
const { typeName, typeParameters } = path.node.id.typeAnnotation.typeAnnotation;
9+
10+
if (!typeParameters) return false;
11+
12+
if (
13+
(typeName.left && typeName.left.name === left && typeName.right.name === right) ||
14+
((right && typeName.name === right) || typeName.name === left)
15+
) {
16+
return true;
17+
}
18+
19+
return false;
20+
}

0 commit comments

Comments
 (0)