@@ -100,8 +100,20 @@ module.exports = function propTypesInstructions(context, components, utils) {
100
100
const defaults = { customValidators : [ ] } ;
101
101
const configuration = Object . assign ( { } , defaults , context . options [ 0 ] || { } ) ;
102
102
const customValidators = configuration . customValidators ;
103
- const allowedGenericTypes = new Set ( [ 'VoidFunctionComponent' , 'PropsWithChildren' , 'SFC' , 'StatelessComponent' , 'FunctionComponent' , 'FC' ] ) ;
103
+ const allowedGenericTypes = new Set ( [ 'forwardRef' , 'ForwardRefRenderFunction' , 'VoidFunctionComponent' , 'PropsWithChildren' , 'SFC' , 'StatelessComponent' , 'FunctionComponent' , 'FC' ] ) ;
104
+ const genericTypeParamIndexWherePropsArePresent = {
105
+ ForwardRefRenderFunction : 1 ,
106
+ forwardRef : 1 ,
107
+ VoidFunctionComponent : 0 ,
108
+ PropsWithChildren : 0 ,
109
+ SFC : 0 ,
110
+ StatelessComponent : 0 ,
111
+ FunctionComponent : 0 ,
112
+ FC : 0 ,
113
+ } ;
104
114
const genericReactTypesImport = new Set ( ) ;
115
+ // import { FC as X } from 'react' -> localToImportedMap = { x: FC }
116
+ const localToImportedMap = { } ;
105
117
106
118
/**
107
119
* Returns the full scope.
@@ -521,9 +533,14 @@ module.exports = function propTypesInstructions(context, components, utils) {
521
533
* @param {ASTNode } node
522
534
* @return {string | undefined }
523
535
*/
524
- function getTypeName ( node ) {
536
+ function getLeftMostTypeName ( node ) {
537
+ if ( node . name ) return node . name ;
538
+ if ( node . left ) return getLeftMostTypeName ( node . left ) ;
539
+ }
540
+
541
+ function getRightMostTypeName ( node ) {
525
542
if ( node . name ) return node . name ;
526
- if ( node . left ) return getTypeName ( node . left ) ;
543
+ if ( node . right ) return getRightMostTypeName ( node . right ) ;
527
544
}
528
545
529
546
class DeclarePropTypesForTSTypeAnnotation {
@@ -579,14 +596,20 @@ module.exports = function propTypesInstructions(context, components, utils) {
579
596
let typeName ;
580
597
if ( astUtil . isTSTypeReference ( node ) ) {
581
598
typeName = node . typeName . name ;
582
- const shouldTraverseTypeParams = genericReactTypesImport . has ( getTypeName ( node . typeName ) ) ;
599
+ const leftMostName = getLeftMostTypeName ( node . typeName ) ;
600
+ const shouldTraverseTypeParams = genericReactTypesImport . has ( leftMostName ) ;
583
601
if ( shouldTraverseTypeParams && node . typeParameters && node . typeParameters . length !== 0 ) {
584
602
// All react Generic types are derived from:
585
603
// type PropsWithChildren<P> = P & { children?: ReactNode | undefined }
586
604
// So we should construct an optional children prop
587
605
this . shouldSpecifyOptionalChildrenProps = true ;
588
606
589
- const nextNode = node . typeParameters . params [ 0 ] ;
607
+ const rightMostName = getRightMostTypeName ( node . typeName ) ;
608
+ const importedName = localToImportedMap [ rightMostName ] ;
609
+ const idx = genericTypeParamIndexWherePropsArePresent [
610
+ leftMostName !== rightMostName ? rightMostName : importedName
611
+ ] ;
612
+ const nextNode = node . typeParameters . params [ idx ] ;
590
613
this . visitTSNode ( nextNode ) ;
591
614
return ;
592
615
}
@@ -941,6 +964,30 @@ module.exports = function propTypesInstructions(context, components, utils) {
941
964
return ;
942
965
}
943
966
967
+ if (
968
+ node . parent
969
+ && node . parent . callee
970
+ && node . parent . typeParameters
971
+ && node . parent . typeParameters . params
972
+ && (
973
+ node . parent . callee . name === 'forwardRef' || (
974
+ node . parent . callee . object
975
+ && node . parent . callee . property
976
+ && node . parent . callee . object . name === 'React'
977
+ && node . parent . callee . property . name === 'forwardRef'
978
+ )
979
+ )
980
+ ) {
981
+ const propTypes = node . parent . typeParameters . params [ 1 ] ;
982
+ const declaredPropTypes = { } ;
983
+ const obj = new DeclarePropTypesForTSTypeAnnotation ( propTypes , declaredPropTypes ) ;
984
+ components . set ( node , {
985
+ declaredPropTypes : obj . declaredPropTypes ,
986
+ ignorePropsValidation : false ,
987
+ } ) ;
988
+ return ;
989
+ }
990
+
944
991
const siblingIdentifier = node . parent && node . parent . id ;
945
992
const siblingHasTypeAnnotation = siblingIdentifier && siblingIdentifier . typeAnnotation ;
946
993
const isNodeAnnotated = annotations . isAnnotatedFunctionPropsDeclaration ( node , context ) ;
@@ -1092,6 +1139,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
1092
1139
// handles import { FC } from 'react' or import { FC as X } from 'react'
1093
1140
if ( specifier . type === 'ImportSpecifier' && allowedGenericTypes . has ( specifier . imported . name ) ) {
1094
1141
genericReactTypesImport . add ( specifier . local . name ) ;
1142
+ localToImportedMap [ specifier . local . name ] = specifier . imported . name ;
1095
1143
}
1096
1144
} ) ;
1097
1145
}
0 commit comments