diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.input.js b/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.input.js new file mode 100644 index 0000000..e056a24 --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.input.js @@ -0,0 +1,10 @@ +import React from "react"; + +type MetaProps = { item: string }; + +const Meta = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithRef & MetaProps +>(({ item: itemProp, asChild, ...rest }, ref) => { + return null; +}); \ No newline at end of file diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.output.js b/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.output.js new file mode 100644 index 0000000..b7722d3 --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/intersection-types.output.js @@ -0,0 +1,16 @@ +import React from "react"; + +type MetaProps = { item: string }; + +const Meta = ( + { + ref, + item: itemProp, + asChild, + ...rest + }: React.ComponentPropsWithRef & MetaProps & { + ref: React.RefObject> + } +) => { + return null; +}; \ No newline at end of file diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.input.js b/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.input.js new file mode 100644 index 0000000..39207c9 --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.input.js @@ -0,0 +1,13 @@ +import React from "react"; + +type BaseProps = { className?: string }; +type MetaProps = { item: string }; +type ButtonProps = { variant: 'primary' | 'secondary' }; +type LinkProps = { href: string }; + +const Meta = React.forwardRef< + HTMLDivElement, + (BaseProps & MetaProps) | (ButtonProps & LinkProps) | ({ icon: 'home' | 'user' | 'settings' } & BaseProps) +>((props: (BaseProps & MetaProps) | (ButtonProps & LinkProps) | ({ icon: 'home' | 'user' | 'settings' } & BaseProps), ref) => { + return null; +}); \ No newline at end of file diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.output.js b/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.output.js new file mode 100644 index 0000000..1898a0f --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/mix-union-intersection-types.output.js @@ -0,0 +1,17 @@ +import React from "react"; + +type BaseProps = { className?: string }; +type MetaProps = { item: string }; +type ButtonProps = { variant: 'primary' | 'secondary' }; +type LinkProps = { href: string }; + +const Meta = ( + { + ref, + ...props + }: (BaseProps & MetaProps) | (ButtonProps & LinkProps) | ({ icon: 'home' | 'user' | 'settings' } & BaseProps) & { + ref: React.RefObject + } +) => { + return null; +}; \ No newline at end of file diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.input.js b/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.input.js new file mode 100644 index 0000000..8076d66 --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.input.js @@ -0,0 +1,11 @@ +import React from "react"; + +type ButtonProps = { variant: 'primary' }; +type LinkProps = { href: string }; + +const Element = React.forwardRef< + HTMLElement, + ButtonProps | LinkProps +>(({ variant, href, ...rest }, ref) => { + return null; +}); \ No newline at end of file diff --git a/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.output.js b/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.output.js new file mode 100644 index 0000000..889d342 --- /dev/null +++ b/transforms/__testfixtures__/remove-forward-ref/typescript/union-types.output.js @@ -0,0 +1,17 @@ +import React from "react"; + +type ButtonProps = { variant: 'primary' }; +type LinkProps = { href: string }; + +const Element = ( + { + ref, + variant, + href, + ...rest + }: ButtonProps | LinkProps & { + ref: React.RefObject + } +) => { + return null; +}; \ No newline at end of file diff --git a/transforms/__tests__/remove-forward-ref.test.ts b/transforms/__tests__/remove-forward-ref.test.ts index 9f76f62..81bb6bf 100644 --- a/transforms/__tests__/remove-forward-ref.test.ts +++ b/transforms/__tests__/remove-forward-ref.test.ts @@ -15,7 +15,10 @@ const tsTests = [ 'type-arguments', 'type-arguments-custom-names', 'type-arguments-type-literals', - 'props-type-literal' + 'props-type-literal', + 'intersection-types', + 'union-types', + 'mix-union-intersection-types' ]; const defineTest = require('jscodeshift/dist/testUtils').defineTest; diff --git a/transforms/remove-forward-ref.ts b/transforms/remove-forward-ref.ts index da7ad9d..5ffd5ab 100644 --- a/transforms/remove-forward-ref.ts +++ b/transforms/remove-forward-ref.ts @@ -6,14 +6,17 @@ import type { FunctionExpression, Identifier, JSCodeshift, + TSIntersectionType, + TSType, TSTypeLiteral, TSTypeReference, + TSUnionType, } from 'jscodeshift'; // Props & { ref: React.RefObject} const buildPropsAndRefIntersectionTypeAnnotation = ( j: JSCodeshift, - propType: TSTypeReference | TSTypeLiteral, + propType: TSType, refType: TSTypeReference | TSTypeLiteral | null, ) => j.tsTypeAnnotation( @@ -94,11 +97,14 @@ const getForwardRefRenderFunction = ( return renderFunction; }; -const isLiteralOrReference = ( +const isSupportedType = ( j: JSCodeshift, type: unknown, -): type is TSTypeReference | TSTypeLiteral => { - return j.TSTypeReference.check(type) || j.TSTypeLiteral.check(type); +): type is TSType => { + return j.TSTypeReference.check(type) || + j.TSTypeLiteral.check(type) || + j.TSIntersectionType.check(type) || + j.TSUnionType.check(type); }; export default function transform(file: FileInfo, api: API) { @@ -220,7 +226,7 @@ export default function transform(file: FileInfo, api: API) { */ if ( - isLiteralOrReference(j, propsArgTypeReference) && + isSupportedType(j, propsArgTypeReference) && renderFunction.params?.[0] && 'typeAnnotation' in renderFunction.params[0] ) { @@ -250,7 +256,7 @@ export default function transform(file: FileInfo, api: API) { if ( j.TSTypeReference.check(refType) && - isLiteralOrReference(j, propType) + isSupportedType(j, propType) ) { renderFunction.params[0].typeAnnotation = buildPropsAndRefIntersectionTypeAnnotation(j, propType, refType);