@@ -251,24 +251,22 @@ function buildInterfaceFromPropTypeObjectLiteral(objectLiteral: ts.ObjectLiteral
251
251
// get d() {}, // AccessorDeclaration
252
252
// }
253
253
. filter ( ts . isPropertyAssignment )
254
- . filter ( property => {
255
- return (
256
- // Ignore children, React types have it
257
- property . name . getText ( ) !== 'children' &&
258
- ts . isPropertyAccessExpression ( property . initializer )
259
- )
260
- } )
254
+ // Ignore children, React types have it
255
+ . filter ( property => property . name . getText ( ) !== 'children' )
261
256
. map ( propertyAssignment => {
262
257
const name = propertyAssignment . name . getText ( ) ;
263
- // We have guarantee this in the previous `filter`
264
- const initializer = propertyAssignment . initializer as ts . PropertyAccessExpression
265
- const typeValue = getTypeFromReactPropTypeExpression ( initializer ) ;
266
- const isOptional = isPropTypeOptional ( initializer ) ;
258
+ const initializer = propertyAssignment . initializer ;
259
+ const isRequired = isPropTypeRequired ( initializer ) ;
260
+ const typeExpression = isRequired
261
+ // We have guaranteed the type in `isPropTypeRequired()`
262
+ ? ( initializer as ts . PropertyAccessExpression ) . expression
263
+ : initializer ;
264
+ const typeValue = getTypeFromReactPropTypeExpression ( typeExpression ) ;
267
265
268
266
return ts . createPropertySignature (
269
267
[ ] ,
270
268
name ,
271
- isOptional ? ts . createToken ( ts . SyntaxKind . QuestionToken ) : undefined ,
269
+ isRequired ? undefined : ts . createToken ( ts . SyntaxKind . QuestionToken ) ,
272
270
typeValue ,
273
271
undefined ,
274
272
) ;
@@ -282,51 +280,138 @@ function buildInterfaceFromPropTypeObjectLiteral(objectLiteral: ts.ObjectLiteral
282
280
*
283
281
* @param node React propTypes value
284
282
*/
285
- function getTypeFromReactPropTypeExpression ( node : ts . PropertyAccessExpression ) {
286
- const text = node . getText ( ) . replace ( / R e a c t \. P r o p T y p e s \. / , '' ) ;
283
+ function getTypeFromReactPropTypeExpression ( node : ts . Expression ) : ts . TypeNode {
287
284
let result = null ;
288
- if ( / s t r i n g / . test ( text ) ) {
289
- result = ts . createKeywordTypeNode ( ts . SyntaxKind . StringKeyword ) ;
290
- } else if ( / a n y / . test ( text ) ) {
291
- result = ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ;
292
- } else if ( / a r r a y / . test ( text ) ) {
293
- result = ts . createArrayTypeNode ( ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ) ;
294
- } else if ( / b o o l / . test ( text ) ) {
295
- result = ts . createKeywordTypeNode ( ts . SyntaxKind . BooleanKeyword ) ;
296
- } else if ( / n u m b e r / . test ( text ) ) {
297
- result = ts . createKeywordTypeNode ( ts . SyntaxKind . NumberKeyword ) ;
298
- } else if ( / o b j e c t / . test ( text ) ) {
299
- result = ts . createKeywordTypeNode ( ts . SyntaxKind . ObjectKeyword ) ;
300
- } else if ( / n o d e / . test ( text ) ) {
301
- result = ts . createTypeReferenceNode ( 'React.ReactNode' , [ ] ) ;
302
- } else if ( / e l e m e n t / . test ( text ) ) {
303
- result = ts . createTypeReferenceNode ( 'JSX.Element' , [ ] ) ;
304
- } else if ( / f u n c / . test ( text ) ) {
305
- const arrayOfAny = ts . createParameter (
306
- [ ] ,
307
- [ ] ,
308
- ts . createToken ( ts . SyntaxKind . DotDotDotToken ) ,
309
- 'args' ,
310
- undefined ,
311
- ts . createArrayTypeNode ( ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ) ,
312
- undefined ,
313
- ) ;
314
- result = ts . createFunctionTypeNode (
315
- [ ] ,
316
- [ arrayOfAny ] ,
317
- ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ,
318
- ) ;
319
- } else {
285
+ if ( ts . isPropertyAccessExpression ( node ) ) {
286
+ /**
287
+ * PropTypes.array,
288
+ * PropTypes.bool,
289
+ * PropTypes.func,
290
+ * PropTypes.number,
291
+ * PropTypes.object,
292
+ * PropTypes.string,
293
+ * PropTypes.symbol, (ignore)
294
+ * PropTypes.node,
295
+ * PropTypes.element,
296
+ * PropTypes.any,
297
+ */
298
+ const text = node . getText ( ) . replace ( / R e a c t \. P r o p T y p e s \. / , '' ) ;
299
+
300
+ if ( / s t r i n g / . test ( text ) ) {
301
+ result = ts . createKeywordTypeNode ( ts . SyntaxKind . StringKeyword ) ;
302
+ } else if ( / a n y / . test ( text ) ) {
303
+ result = ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ;
304
+ } else if ( / a r r a y / . test ( text ) ) {
305
+ result = ts . createArrayTypeNode ( ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ) ;
306
+ } else if ( / b o o l / . test ( text ) ) {
307
+ result = ts . createKeywordTypeNode ( ts . SyntaxKind . BooleanKeyword ) ;
308
+ } else if ( / n u m b e r / . test ( text ) ) {
309
+ result = ts . createKeywordTypeNode ( ts . SyntaxKind . NumberKeyword ) ;
310
+ } else if ( / o b j e c t / . test ( text ) ) {
311
+ result = ts . createKeywordTypeNode ( ts . SyntaxKind . ObjectKeyword ) ;
312
+ } else if ( / n o d e / . test ( text ) ) {
313
+ result = ts . createTypeReferenceNode ( 'React.ReactNode' , [ ] ) ;
314
+ } else if ( / e l e m e n t / . test ( text ) ) {
315
+ result = ts . createTypeReferenceNode ( 'JSX.Element' , [ ] ) ;
316
+ } else if ( / f u n c / . test ( text ) ) {
317
+ const arrayOfAny = ts . createParameter (
318
+ [ ] ,
319
+ [ ] ,
320
+ ts . createToken ( ts . SyntaxKind . DotDotDotToken ) ,
321
+ 'args' ,
322
+ undefined ,
323
+ ts . createArrayTypeNode ( ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ) ,
324
+ undefined ,
325
+ ) ;
326
+ result = ts . createFunctionTypeNode (
327
+ [ ] ,
328
+ [ arrayOfAny ] ,
329
+ ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ,
330
+ ) ;
331
+ }
332
+ } else if ( ts . isCallExpression ( node ) ) {
333
+ /**
334
+ * PropTypes.instanceOf(), (ignore)
335
+ * PropTypes.oneOf(), // only support oneOf([1, 2]), oneOf(['a', 'b'])
336
+ * PropTypes.oneOfType(),
337
+ * PropTypes.arrayOf(),
338
+ * PropTypes.objectOf(),
339
+ * PropTypes.shape(),
340
+ */
341
+ const text = node . expression . getText ( ) ;
342
+ if ( / o n e O f $ / . test ( text ) ) {
343
+ const argument = node . arguments [ 0 ] ;
344
+ if ( ts . isArrayLiteralExpression ( argument ) ) {
345
+ if ( argument . elements . every ( elm => ts . isStringLiteral ( elm ) || ts . isNumericLiteral ( elm ) ) ) {
346
+ result = ts . createUnionTypeNode (
347
+ ( argument . elements as ts . NodeArray < ts . StringLiteral | ts . NumericLiteral > ) . map ( elm =>
348
+ ts . createLiteralTypeNode ( elm )
349
+ ) ,
350
+ )
351
+ }
352
+ }
353
+ } else if ( / o n e O f T y p e $ / . test ( text ) ) {
354
+ const argument = node . arguments [ 0 ] ;
355
+ if ( ts . isArrayLiteralExpression ( argument ) ) {
356
+ result = ts . createUnionOrIntersectionTypeNode (
357
+ ts . SyntaxKind . UnionType ,
358
+ argument . elements . map ( elm => getTypeFromReactPropTypeExpression ( elm ) ) ,
359
+ ) ;
360
+ }
361
+ } else if ( / a r r a y O f $ / . test ( text ) ) {
362
+ const argument = node . arguments [ 0 ] ;
363
+ if ( argument ) {
364
+ result = ts . createArrayTypeNode (
365
+ getTypeFromReactPropTypeExpression ( argument )
366
+ )
367
+ }
368
+ } else if ( / o b j e c t O f $ / . test ( text ) ) {
369
+ const argument = node . arguments [ 0 ] ;
370
+ if ( argument ) {
371
+ result = ts . createTypeLiteralNode ( [
372
+ ts . createIndexSignature (
373
+ undefined ,
374
+ undefined ,
375
+ [
376
+ ts . createParameter (
377
+ undefined ,
378
+ undefined ,
379
+ undefined ,
380
+ 'key' ,
381
+ undefined ,
382
+ ts . createKeywordTypeNode ( ts . SyntaxKind . StringKeyword ) ,
383
+ )
384
+ ] ,
385
+ getTypeFromReactPropTypeExpression ( argument ) ,
386
+ )
387
+ ] )
388
+ }
389
+ } else if ( / s h a p e $ / . test ( text ) ) {
390
+ const argument = node . arguments [ 0 ] ;
391
+ if ( ts . isObjectLiteralExpression ( argument ) ) {
392
+ return buildInterfaceFromPropTypeObjectLiteral ( argument )
393
+ }
394
+ }
395
+ }
396
+
397
+ /**
398
+ * customProp,
399
+ * anything others
400
+ */
401
+ if ( result === null ) {
320
402
result = ts . createKeywordTypeNode ( ts . SyntaxKind . AnyKeyword ) ;
321
403
}
322
- return result ;
404
+
405
+ return result
323
406
}
324
407
325
408
/**
326
- * Decide if node is optional
409
+ * Decide if node is required
327
410
* @param node React propTypes member node
328
411
*/
329
- function isPropTypeOptional ( node : ts . PropertyAccessExpression ) {
412
+ function isPropTypeRequired ( node : ts . Expression ) {
413
+ if ( ! ts . isPropertyAccessExpression ( node ) ) return false ;
414
+
330
415
const text = node . getText ( ) . replace ( / R e a c t \. P r o p T y p e s \. / , '' ) ;
331
- return ! / \. i s R e q u i r e d / . test ( text )
416
+ return / \. i s R e q u i r e d / . test ( text ) ;
332
417
}
0 commit comments