Skip to content

Commit

Permalink
✨ Adds support for React.FC & FC (#183)
Browse files Browse the repository at this point in the history
* ✨ Adds support for React.FC & FC

* docs(changeset): Adds support for React.FC and FC
  • Loading branch information
danieldelcore authored Apr 19, 2021
1 parent 0b9456e commit 7a46827
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/tough-crews-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'extract-react-types': patch
---

Adds support for React.FC and FC
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,69 @@ Object {
}
`;

exports[`TypeScript: FC 1`] = `
Object {
"kind": "generic",
"name": Object {
"kind": "id",
"name": "Component",
"type": null,
},
"value": Object {
"kind": "object",
"members": Array [
Object {
"key": Object {
"kind": "id",
"name": "children",
},
"kind": "property",
"optional": false,
"value": Object {
"kind": "string",
},
},
],
"referenceIdName": "Props",
},
}
`;

exports[`TypeScript: FC with empty type argument 1`] = `
Object {
"kind": "any",
"name": Object {
"kind": "id",
"name": "Component",
"type": null,
},
}
`;

exports[`TypeScript: FC with inline type argument 1`] = `
Object {
"kind": "object",
"members": Array [
Object {
"key": Object {
"kind": "id",
"name": "children",
},
"kind": "property",
"optional": false,
"value": Object {
"kind": "string",
},
},
],
"name": Object {
"kind": "id",
"name": "Component",
"type": null,
},
}
`;

exports[`TypeScript: React.ComponentType 1`] = `
Object {
"kind": "generic",
Expand Down
47 changes: 44 additions & 3 deletions packages/extract-react-types/converters-typescript.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const TESTS = [
`
},
{
name: 'React.FC',
name: 'FC',
typeSystem: 'typescript',
code: `
type Props = {
Expand All @@ -78,7 +78,7 @@ const TESTS = [
`
},
{
name: 'React.FC with empty type argument',
name: 'FC with empty type argument',
typeSystem: 'typescript',
code: `
type Props = {
Expand All @@ -91,7 +91,7 @@ const TESTS = [
`
},
{
name: 'React.FC with inline type argument',
name: 'FC with inline type argument',
typeSystem: 'typescript',
code: `
const Component: FC<{
Expand All @@ -101,6 +101,47 @@ const TESTS = [
export default Component;
`
},
{
name: 'React.FC',
typeSystem: 'typescript',
code: `
import React from 'react';
type Props = {
children: string;
};
const Component: React.FC<Props> = (props) => null;
export default Component;
`
},
{
name: 'React.FC with empty type argument',
typeSystem: 'typescript',
code: `
import React from 'react';
type Props = {
children: string;
};
const Component: React.FC = (props) => null;
export default Component;
`
},
{
name: 'React.FC with inline type argument',
typeSystem: 'typescript',
code: `
const Component: React.FC<{
children: string;
}> = (props) => null;
export default Component;
`
},
{
name: 'Direct type assignment',
typeSystem: 'typescript',
Expand Down
11 changes: 3 additions & 8 deletions packages/extract-react-types/src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
hasDestructuredDefaultExport,
matchExported
} from './export-manager';

import { hasTypeAnnotation } from './utils';
import * as K from './kinds';

const converters = {};
Expand Down Expand Up @@ -1277,13 +1277,8 @@ export function convertComponentExports(componentExports, context) {
) {
let propType;

// check for a component typed with the `FC<Props>` annotation
if (
path.parentPath.node.id &&
path.parentPath.node.id.typeAnnotation &&
path.parentPath.node.id.typeAnnotation.typeAnnotation.typeName.name === 'FC' &&
path.parentPath.node.id.typeAnnotation.typeAnnotation.typeParameters
) {
// check for a component typed with the `React.FC<Props>` or `FC<Props>` type annotation
if (hasTypeAnnotation(path.parentPath, 'React', 'FC')) {
propType = path.parentPath.get('id.typeAnnotation.typeAnnotation.typeParameters.params.0');
} else {
// we have a normal function, assume the props are the first parameter
Expand Down
20 changes: 20 additions & 0 deletions packages/extract-react-types/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable import/prefer-default-export */

export function hasTypeAnnotation(path, left, right) {
if (!path.isVariableDeclarator() || !path.node.id.typeAnnotation) {
return false;
}

const { typeName, typeParameters } = path.node.id.typeAnnotation.typeAnnotation;

if (!typeParameters) return false;

if (
(typeName.left && typeName.left.name === left && typeName.right.name === right) ||
((right && typeName.name === right) || typeName.name === left)
) {
return true;
}

return false;
}

0 comments on commit 7a46827

Please sign in to comment.