@@ -1180,156 +1180,164 @@ export function inferRuntimeType(
1180
1180
node : Node & MaybeWithScope ,
1181
1181
scope = node . _ownerScope || ctxToScope ( ctx )
1182
1182
) : string [ ] {
1183
- switch ( node . type ) {
1184
- case 'TSStringKeyword' :
1185
- return [ 'String' ]
1186
- case 'TSNumberKeyword' :
1187
- return [ 'Number' ]
1188
- case 'TSBooleanKeyword' :
1189
- return [ 'Boolean' ]
1190
- case 'TSObjectKeyword' :
1191
- return [ 'Object' ]
1192
- case 'TSNullKeyword' :
1193
- return [ 'null' ]
1194
- case 'TSTypeLiteral' :
1195
- case 'TSInterfaceDeclaration' : {
1196
- // TODO (nice to have) generate runtime property validation
1197
- const types = new Set < string > ( )
1198
- const members =
1199
- node . type === 'TSTypeLiteral' ? node . members : node . body . body
1200
- for ( const m of members ) {
1201
- if (
1202
- m . type === 'TSCallSignatureDeclaration' ||
1203
- m . type === 'TSConstructSignatureDeclaration'
1204
- ) {
1205
- types . add ( 'Function' )
1206
- } else {
1207
- types . add ( 'Object' )
1183
+ try {
1184
+ switch ( node . type ) {
1185
+ case 'TSStringKeyword' :
1186
+ return [ 'String' ]
1187
+ case 'TSNumberKeyword' :
1188
+ return [ 'Number' ]
1189
+ case 'TSBooleanKeyword' :
1190
+ return [ 'Boolean' ]
1191
+ case 'TSObjectKeyword' :
1192
+ return [ 'Object' ]
1193
+ case 'TSNullKeyword' :
1194
+ return [ 'null' ]
1195
+ case 'TSTypeLiteral' :
1196
+ case 'TSInterfaceDeclaration' : {
1197
+ // TODO (nice to have) generate runtime property validation
1198
+ const types = new Set < string > ( )
1199
+ const members =
1200
+ node . type === 'TSTypeLiteral' ? node . members : node . body . body
1201
+ for ( const m of members ) {
1202
+ if (
1203
+ m . type === 'TSCallSignatureDeclaration' ||
1204
+ m . type === 'TSConstructSignatureDeclaration'
1205
+ ) {
1206
+ types . add ( 'Function' )
1207
+ } else {
1208
+ types . add ( 'Object' )
1209
+ }
1208
1210
}
1211
+ return types . size ? Array . from ( types ) : [ 'Object' ]
1209
1212
}
1210
- return types . size ? Array . from ( types ) : [ 'Object' ]
1211
- }
1212
- case 'TSPropertySignature' :
1213
- if ( node . typeAnnotation ) {
1214
- return inferRuntimeType ( ctx , node . typeAnnotation . typeAnnotation , scope )
1215
- }
1216
- case 'TSMethodSignature' :
1217
- case 'TSFunctionType' :
1218
- return [ 'Function' ]
1219
- case 'TSArrayType' :
1220
- case 'TSTupleType' :
1221
- // TODO (nice to have) generate runtime element type/length checks
1222
- return [ 'Array' ]
1223
-
1224
- case 'TSLiteralType' :
1225
- switch ( node . literal . type ) {
1226
- case 'StringLiteral' :
1227
- return [ 'String' ]
1228
- case 'BooleanLiteral' :
1229
- return [ 'Boolean' ]
1230
- case 'NumericLiteral' :
1231
- case 'BigIntLiteral' :
1232
- return [ 'Number' ]
1233
- default :
1234
- return [ UNKNOWN_TYPE ]
1235
- }
1236
-
1237
- case 'TSTypeReference' : {
1238
- const resolved = resolveTypeReference ( ctx , node , scope )
1239
- if ( resolved ) {
1240
- return inferRuntimeType ( ctx , resolved , resolved . _ownerScope )
1241
- }
1242
- if ( node . typeName . type === 'Identifier' ) {
1243
- switch ( node . typeName . name ) {
1244
- case 'Array' :
1245
- case 'Function' :
1246
- case 'Object' :
1247
- case 'Set' :
1248
- case 'Map' :
1249
- case 'WeakSet' :
1250
- case 'WeakMap' :
1251
- case 'Date' :
1252
- case 'Promise' :
1253
- return [ node . typeName . name ]
1254
-
1255
- // TS built-in utility types
1256
- // https://www.typescriptlang.org/docs/handbook/utility-types.html
1257
- case 'Partial' :
1258
- case 'Required' :
1259
- case 'Readonly' :
1260
- case 'Record' :
1261
- case 'Pick' :
1262
- case 'Omit' :
1263
- case 'InstanceType' :
1264
- return [ 'Object' ]
1265
-
1266
- case 'Uppercase' :
1267
- case 'Lowercase' :
1268
- case 'Capitalize' :
1269
- case 'Uncapitalize' :
1213
+ case 'TSPropertySignature' :
1214
+ if ( node . typeAnnotation ) {
1215
+ return inferRuntimeType (
1216
+ ctx ,
1217
+ node . typeAnnotation . typeAnnotation ,
1218
+ scope
1219
+ )
1220
+ }
1221
+ case 'TSMethodSignature' :
1222
+ case 'TSFunctionType' :
1223
+ return [ 'Function' ]
1224
+ case 'TSArrayType' :
1225
+ case 'TSTupleType' :
1226
+ // TODO (nice to have) generate runtime element type/length checks
1227
+ return [ 'Array' ]
1228
+
1229
+ case 'TSLiteralType' :
1230
+ switch ( node . literal . type ) {
1231
+ case 'StringLiteral' :
1270
1232
return [ 'String' ]
1233
+ case 'BooleanLiteral' :
1234
+ return [ 'Boolean' ]
1235
+ case 'NumericLiteral' :
1236
+ case 'BigIntLiteral' :
1237
+ return [ 'Number' ]
1238
+ default :
1239
+ return [ UNKNOWN_TYPE ]
1240
+ }
1271
1241
1272
- case 'Parameters' :
1273
- case 'ConstructorParameters' :
1274
- return [ 'Array' ]
1275
-
1276
- case 'NonNullable' :
1277
- if ( node . typeParameters && node . typeParameters . params [ 0 ] ) {
1278
- return inferRuntimeType (
1279
- ctx ,
1280
- node . typeParameters . params [ 0 ] ,
1281
- scope
1282
- ) . filter ( t => t !== 'null' )
1283
- }
1284
- break
1285
- case 'Extract' :
1286
- if ( node . typeParameters && node . typeParameters . params [ 1 ] ) {
1287
- return inferRuntimeType ( ctx , node . typeParameters . params [ 1 ] , scope )
1288
- }
1289
- break
1290
- case 'Exclude' :
1291
- case 'OmitThisParameter' :
1292
- if ( node . typeParameters && node . typeParameters . params [ 0 ] ) {
1293
- return inferRuntimeType ( ctx , node . typeParameters . params [ 0 ] , scope )
1294
- }
1295
- break
1242
+ case 'TSTypeReference' : {
1243
+ const resolved = resolveTypeReference ( ctx , node , scope )
1244
+ if ( resolved ) {
1245
+ return inferRuntimeType ( ctx , resolved , resolved . _ownerScope )
1246
+ }
1247
+ if ( node . typeName . type === 'Identifier' ) {
1248
+ switch ( node . typeName . name ) {
1249
+ case 'Array' :
1250
+ case 'Function' :
1251
+ case 'Object' :
1252
+ case 'Set' :
1253
+ case 'Map' :
1254
+ case 'WeakSet' :
1255
+ case 'WeakMap' :
1256
+ case 'Date' :
1257
+ case 'Promise' :
1258
+ return [ node . typeName . name ]
1259
+
1260
+ // TS built-in utility types
1261
+ // https://www.typescriptlang.org/docs/handbook/utility-types.html
1262
+ case 'Partial' :
1263
+ case 'Required' :
1264
+ case 'Readonly' :
1265
+ case 'Record' :
1266
+ case 'Pick' :
1267
+ case 'Omit' :
1268
+ case 'InstanceType' :
1269
+ return [ 'Object' ]
1270
+
1271
+ case 'Uppercase' :
1272
+ case 'Lowercase' :
1273
+ case 'Capitalize' :
1274
+ case 'Uncapitalize' :
1275
+ return [ 'String' ]
1276
+
1277
+ case 'Parameters' :
1278
+ case 'ConstructorParameters' :
1279
+ return [ 'Array' ]
1280
+
1281
+ case 'NonNullable' :
1282
+ if ( node . typeParameters && node . typeParameters . params [ 0 ] ) {
1283
+ return inferRuntimeType (
1284
+ ctx ,
1285
+ node . typeParameters . params [ 0 ] ,
1286
+ scope
1287
+ ) . filter ( t => t !== 'null' )
1288
+ }
1289
+ break
1290
+ case 'Extract' :
1291
+ if ( node . typeParameters && node . typeParameters . params [ 1 ] ) {
1292
+ return inferRuntimeType (
1293
+ ctx ,
1294
+ node . typeParameters . params [ 1 ] ,
1295
+ scope
1296
+ )
1297
+ }
1298
+ break
1299
+ case 'Exclude' :
1300
+ case 'OmitThisParameter' :
1301
+ if ( node . typeParameters && node . typeParameters . params [ 0 ] ) {
1302
+ return inferRuntimeType (
1303
+ ctx ,
1304
+ node . typeParameters . params [ 0 ] ,
1305
+ scope
1306
+ )
1307
+ }
1308
+ break
1309
+ }
1296
1310
}
1311
+ // cannot infer, fallback to UNKNOWN: ThisParameterType
1312
+ break
1297
1313
}
1298
- // cannot infer, fallback to UNKNOWN: ThisParameterType
1299
- break
1300
- }
1301
1314
1302
- case 'TSParenthesizedType' :
1303
- return inferRuntimeType ( ctx , node . typeAnnotation , scope )
1315
+ case 'TSParenthesizedType' :
1316
+ return inferRuntimeType ( ctx , node . typeAnnotation , scope )
1304
1317
1305
- case 'TSUnionType' :
1306
- return flattenTypes ( ctx , node . types , scope )
1307
- case 'TSIntersectionType' : {
1308
- return flattenTypes ( ctx , node . types , scope ) . filter (
1309
- t => t !== UNKNOWN_TYPE
1310
- )
1311
- }
1318
+ case 'TSUnionType' :
1319
+ return flattenTypes ( ctx , node . types , scope )
1320
+ case 'TSIntersectionType' : {
1321
+ return flattenTypes ( ctx , node . types , scope ) . filter (
1322
+ t => t !== UNKNOWN_TYPE
1323
+ )
1324
+ }
1312
1325
1313
- case 'TSEnumDeclaration' :
1314
- return inferEnumType ( node )
1326
+ case 'TSEnumDeclaration' :
1327
+ return inferEnumType ( node )
1315
1328
1316
- case 'TSSymbolKeyword' :
1317
- return [ 'Symbol' ]
1329
+ case 'TSSymbolKeyword' :
1330
+ return [ 'Symbol' ]
1318
1331
1319
- case 'TSIndexedAccessType' : {
1320
- try {
1332
+ case 'TSIndexedAccessType' : {
1321
1333
const types = resolveIndexType ( ctx , node , scope )
1322
1334
return flattenTypes ( ctx , types , scope )
1323
- } catch ( e ) {
1324
- break
1325
1335
}
1326
- }
1327
1336
1328
- case 'ClassDeclaration' :
1329
- return [ 'Object' ]
1337
+ case 'ClassDeclaration' :
1338
+ return [ 'Object' ]
1330
1339
1331
- case 'TSImportType' : {
1332
- try {
1340
+ case 'TSImportType' : {
1333
1341
const sourceScope = importSourceToScope (
1334
1342
ctx ,
1335
1343
node . argument ,
@@ -1340,21 +1348,23 @@ export function inferRuntimeType(
1340
1348
if ( resolved ) {
1341
1349
return inferRuntimeType ( ctx , resolved , resolved . _ownerScope )
1342
1350
}
1343
- } catch ( e ) { }
1344
- break
1345
- }
1351
+ break
1352
+ }
1346
1353
1347
- case 'TSTypeQuery' : {
1348
- const id = node . exprName
1349
- if ( id . type === 'Identifier' ) {
1350
- // typeof only support identifier in local scope
1351
- const matched = scope . declares [ id . name ]
1352
- if ( matched ) {
1353
- return inferRuntimeType ( ctx , matched , matched . _ownerScope )
1354
+ case 'TSTypeQuery' : {
1355
+ const id = node . exprName
1356
+ if ( id . type === 'Identifier' ) {
1357
+ // typeof only support identifier in local scope
1358
+ const matched = scope . declares [ id . name ]
1359
+ if ( matched ) {
1360
+ return inferRuntimeType ( ctx , matched , matched . _ownerScope )
1361
+ }
1354
1362
}
1363
+ break
1355
1364
}
1356
- break
1357
1365
}
1366
+ } catch ( e ) {
1367
+ // always soft fail on failed runtime type inference
1358
1368
}
1359
1369
return [ UNKNOWN_TYPE ] // no runtime check
1360
1370
}
0 commit comments