@@ -1448,7 +1448,10 @@ export function inferRuntimeType(
1448
1448
ctx : TypeResolveContext ,
1449
1449
node : Node & MaybeWithScope ,
1450
1450
scope = node . _ownerScope || ctxToScope ( ctx ) ,
1451
+ options : { isKeyof ?: boolean } = { } ,
1451
1452
) : string [ ] {
1453
+ const { isKeyof } = options
1454
+
1452
1455
try {
1453
1456
switch ( node . type ) {
1454
1457
case 'TSStringKeyword' :
@@ -1467,16 +1470,33 @@ export function inferRuntimeType(
1467
1470
const types = new Set < string > ( )
1468
1471
const members =
1469
1472
node . type === 'TSTypeLiteral' ? node . members : node . body . body
1473
+
1474
+ const handler = isKeyof
1475
+ ? ( m : TSTypeElement ) => {
1476
+ if (
1477
+ m . type === 'TSPropertySignature' &&
1478
+ m . key . type === 'NumericLiteral'
1479
+ ) {
1480
+ types . add ( 'Number' )
1481
+ } else {
1482
+ types . add ( 'String' )
1483
+ }
1484
+ }
1485
+ : ( m : TSTypeElement ) => {
1486
+ if (
1487
+ m . type === 'TSCallSignatureDeclaration' ||
1488
+ m . type === 'TSConstructSignatureDeclaration'
1489
+ ) {
1490
+ types . add ( 'Function' )
1491
+ } else {
1492
+ types . add ( 'Object' )
1493
+ }
1494
+ }
1495
+
1470
1496
for ( const m of members ) {
1471
- if (
1472
- m . type === 'TSCallSignatureDeclaration' ||
1473
- m . type === 'TSConstructSignatureDeclaration'
1474
- ) {
1475
- types . add ( 'Function' )
1476
- } else {
1477
- types . add ( 'Object' )
1478
- }
1497
+ handler ( m )
1479
1498
}
1499
+
1480
1500
return types . size ? Array . from ( types ) : [ 'Object' ]
1481
1501
}
1482
1502
case 'TSPropertySignature' :
@@ -1512,9 +1532,22 @@ export function inferRuntimeType(
1512
1532
case 'TSTypeReference' : {
1513
1533
const resolved = resolveTypeReference ( ctx , node , scope )
1514
1534
if ( resolved ) {
1515
- return inferRuntimeType ( ctx , resolved , resolved . _ownerScope )
1535
+ return inferRuntimeType ( ctx , resolved , resolved . _ownerScope , options )
1516
1536
}
1537
+
1517
1538
if ( node . typeName . type === 'Identifier' ) {
1539
+ if ( isKeyof ) {
1540
+ switch ( node . typeName . name ) {
1541
+ case 'String' :
1542
+ case 'Array' :
1543
+ case 'ArrayLike' :
1544
+ case 'ReadonlyArray' :
1545
+ return [ 'String' , 'Number' ]
1546
+ default :
1547
+ return [ 'String' ]
1548
+ }
1549
+ }
1550
+
1518
1551
switch ( node . typeName . name ) {
1519
1552
case 'Array' :
1520
1553
case 'Function' :
@@ -1634,15 +1667,17 @@ export function inferRuntimeType(
1634
1667
// typeof only support identifier in local scope
1635
1668
const matched = scope . declares [ id . name ]
1636
1669
if ( matched ) {
1637
- return inferRuntimeType ( ctx , matched , matched . _ownerScope )
1670
+ return inferRuntimeType ( ctx , matched , matched . _ownerScope , options )
1638
1671
}
1639
1672
}
1640
1673
break
1641
1674
}
1642
1675
1643
1676
// e.g. readonly
1644
1677
case 'TSTypeOperator' : {
1645
- return inferRuntimeType ( ctx , node . typeAnnotation , scope )
1678
+ return inferRuntimeType ( ctx , node . typeAnnotation , scope , {
1679
+ isKeyof : node . operator === 'keyof' ,
1680
+ } )
1646
1681
}
1647
1682
}
1648
1683
} catch ( e ) {
0 commit comments