@@ -18,7 +18,9 @@ import isUnreachableFlowType from '../utils/isUnreachableFlowType';
18
18
import recast from 'recast' ;
19
19
import resolveToValue from '../utils/resolveToValue' ;
20
20
21
- var { types : { namedTypes : types } } = recast ;
21
+ const { types : { namedTypes : types } } = recast ;
22
+
23
+ const supportedUtilityTypes = new Set ( [ '$Exact' , '$ReadOnly' ] ) ;
22
24
23
25
/**
24
26
* Given an React component (stateless or class) tries to find the
@@ -52,7 +54,9 @@ export default (path: NodePath): ?NodePath => {
52
54
typePath = getTypeAnnotation ( param ) ;
53
55
}
54
56
55
- if ( typePath && types . GenericTypeAnnotation . check ( typePath . node ) ) {
57
+ if ( typePath && isSupportedUtilityType ( typePath ) ) {
58
+ typePath = unwrapUtilityType ( typePath ) ;
59
+ } else if ( typePath && types . GenericTypeAnnotation . check ( typePath . node ) ) {
56
60
typePath = resolveToValue ( typePath . get ( 'id' ) ) ;
57
61
if (
58
62
! typePath ||
@@ -93,7 +97,9 @@ export function applyToFlowTypeProperties(
93
97
function resolveGenericTypeAnnotation ( path : NodePath ) : ?NodePath {
94
98
// If the node doesn't have types or properties, try to get the type.
95
99
let typePath : ?NodePath ;
96
- if ( path && types . GenericTypeAnnotation . check ( path . node ) ) {
100
+ if ( path && isSupportedUtilityType ( path ) ) {
101
+ typePath = unwrapUtilityType ( path ) ;
102
+ } else if ( path && types . GenericTypeAnnotation . check ( path . node ) ) {
97
103
typePath = resolveToValue ( path . get ( 'id' ) ) ;
98
104
if ( isUnreachableFlowType ( typePath ) ) {
99
105
return ;
@@ -104,3 +110,25 @@ function resolveGenericTypeAnnotation(path: NodePath): ?NodePath {
104
110
105
111
return typePath ;
106
112
}
113
+
114
+ /**
115
+ * See `supportedUtilityTypes` for which types are supported and
116
+ * https://flow.org/en/docs/types/utilities/ for which types are available.
117
+ */
118
+ function isSupportedUtilityType ( path : NodePath ) : boolean {
119
+ if ( types . GenericTypeAnnotation . check ( path . node ) ) {
120
+ const idPath = path . get ( 'id' ) ;
121
+ return Boolean ( idPath ) &&
122
+ supportedUtilityTypes . has ( idPath . node . name ) ;
123
+ }
124
+ return false ;
125
+ }
126
+
127
+ /**
128
+ * Unwraps well known utility types. For example:
129
+ *
130
+ * $ReadOnly<T> => T
131
+ */
132
+ function unwrapUtilityType ( path : NodePath ) : ?NodePath {
133
+ return path . get ( 'typeParameters' , 'params' , 0 ) ;
134
+ }
0 commit comments