@@ -1448,7 +1448,10 @@ export function inferRuntimeType(
14481448 ctx : TypeResolveContext ,
14491449 node : Node & MaybeWithScope ,
14501450 scope = node . _ownerScope || ctxToScope ( ctx ) ,
1451+ options : { isKeyof ?: boolean } = { } ,
14511452) : string [ ] {
1453+ const { isKeyof } = options
1454+
14521455 try {
14531456 switch ( node . type ) {
14541457 case 'TSStringKeyword' :
@@ -1467,16 +1470,33 @@ export function inferRuntimeType(
14671470 const types = new Set < string > ( )
14681471 const members =
14691472 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+
14701496 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 )
14791498 }
1499+
14801500 return types . size ? Array . from ( types ) : [ 'Object' ]
14811501 }
14821502 case 'TSPropertySignature' :
@@ -1512,9 +1532,22 @@ export function inferRuntimeType(
15121532 case 'TSTypeReference' : {
15131533 const resolved = resolveTypeReference ( ctx , node , scope )
15141534 if ( resolved ) {
1515- return inferRuntimeType ( ctx , resolved , resolved . _ownerScope )
1535+ return inferRuntimeType ( ctx , resolved , resolved . _ownerScope , options )
15161536 }
1537+
15171538 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+
15181551 switch ( node . typeName . name ) {
15191552 case 'Array' :
15201553 case 'Function' :
@@ -1634,15 +1667,17 @@ export function inferRuntimeType(
16341667 // typeof only support identifier in local scope
16351668 const matched = scope . declares [ id . name ]
16361669 if ( matched ) {
1637- return inferRuntimeType ( ctx , matched , matched . _ownerScope )
1670+ return inferRuntimeType ( ctx , matched , matched . _ownerScope , options )
16381671 }
16391672 }
16401673 break
16411674 }
16421675
16431676 // e.g. readonly
16441677 case 'TSTypeOperator' : {
1645- return inferRuntimeType ( ctx , node . typeAnnotation , scope )
1678+ return inferRuntimeType ( ctx , node . typeAnnotation , scope , {
1679+ isKeyof : node . operator === 'keyof' ,
1680+ } )
16461681 }
16471682 }
16481683 } catch ( e ) {
0 commit comments