Skip to content

Commit

Permalink
✨ Add support for memo typed with generics (#159)
Browse files Browse the repository at this point in the history
* ✨ Add support for memo typed with generics

* docs(changeset): Add support for memos typed with generics
  • Loading branch information
danieldelcore committed Feb 18, 2021
1 parent e54d851 commit 683eac7
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/shiny-cows-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'extract-react-types': minor
---

Add support for memos typed with generics
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,62 @@ Object {
}
`;

exports[`TypeScript: memo typed via generic types 1`] = `
Object {
"kind": "generic",
"name": Object {
"kind": "id",
"name": "MyComponent",
"type": null,
},
"value": Object {
"kind": "object",
"members": Array [
Object {
"key": Object {
"kind": "id",
"name": "foo",
},
"kind": "property",
"optional": false,
"value": Object {
"kind": "string",
},
},
],
"referenceIdName": "MyComponentProps",
},
}
`;

exports[`TypeScript: memo wrapping forwardRef, both typed via generic types 1`] = `
Object {
"kind": "generic",
"name": Object {
"kind": "id",
"name": "MyComponent",
"type": null,
},
"value": Object {
"kind": "object",
"members": Array [
Object {
"key": Object {
"kind": "id",
"name": "foo",
},
"kind": "property",
"optional": false,
"value": Object {
"kind": "string",
},
},
],
"referenceIdName": "MyComponentProps",
},
}
`;

exports[`TypeScript: ts any 1`] = `
Object {
"kind": "object",
Expand Down
34 changes: 34 additions & 0 deletions packages/extract-react-types/converters-typescript.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,40 @@ const TESTS = [
export default MyComponent;
`
},
{
name: 'memo typed via generic types',
typeSystem: 'typescript',
code: `
import React, { forwardRef, memo } from 'react';
type MyComponentProps = {
foo: string,
}
const MyComponent = memo<MyComponentProps>((props, ref) => {
return <span>Foo</span>;
});
export default MyComponent;
`
},
{
name: 'memo wrapping forwardRef, both typed via generic types',
typeSystem: 'typescript',
code: `
import React, { forwardRef, memo } from 'react';
type MyComponentProps = {
foo: string,
}
const MyComponent = memo<MyComponentProps>(forwardRef<HTMLElement, MyComponentProps>((props, ref) => {
return <span>Foo</span>;
}));
export default MyComponent;
`
}
];

Expand Down
26 changes: 15 additions & 11 deletions packages/extract-react-types/src/findExports.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import { loadFileSync, resolveImportFilePathSync } from 'babel-file-loader';

export function hasDestructuredDefaultExport(path) {
const exportPath = path.get('body').find(bodyPath => {
return (
bodyPath.isExportNamedDeclaration() &&
bodyPath.get('specifiers').filter(n => n.node.exported.name === 'default').length
const exportPath = path
.get('body')
.find(
bodyPath =>
bodyPath.isExportNamedDeclaration() &&
bodyPath.get('specifiers').filter(n => n.node.exported.name === 'default').length
);
});

return Boolean(exportPath);
}

export function followExports(path, context, convert) {
const exportPath = path.get('body').find(bodyPath => {
return (
bodyPath.isExportNamedDeclaration() &&
bodyPath.get('specifiers').filter(n => n.node.exported.name === 'default')
const exportPath = path
.get('body')
.find(
bodyPath =>
bodyPath.isExportNamedDeclaration() &&
bodyPath.get('specifiers').filter(n => n.node.exported.name === 'default')
);
});

if (!exportPath)
if (!exportPath) {
throw new Error({
message: 'No export path found'
});
}

try {
const filePath = resolveImportFilePathSync(exportPath, context.resolveOptions);
Expand Down
15 changes: 14 additions & 1 deletion packages/extract-react-types/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,7 @@ function exportedComponents(programPath, componentsToFind: 'all' | 'default', co
components.push({ name, path, component });
return;
}

if (path.isClass()) {
let component = convertReactComponentClass(path, context);
components.push({ name, path, component });
Expand All @@ -1380,7 +1381,7 @@ function exportedComponents(programPath, componentsToFind: 'all' | 'default', co
const genericTypeParams = path.get('typeParameters');

// Props are the second type arg
if (isForwardRef && genericTypeParams && genericTypeParams.node) {
if (isForwardRef && genericTypeParams.node) {
const component = convertReactComponentFunction(
genericTypeParams,
context,
Expand All @@ -1392,6 +1393,18 @@ function exportedComponents(programPath, componentsToFind: 'all' | 'default', co
return;
}

if (isMemo && genericTypeParams.node) {
const component = convertReactComponentFunction(
genericTypeParams,
context,
genericTypeParams.get('params.0')
);

components.push({ name, path, component });

return;
}

// Props typed via function arguments
const firstArg = path.get('arguments')[0];

Expand Down

0 comments on commit 683eac7

Please sign in to comment.