@@ -354,6 +354,35 @@ export function processFunctionDeclaration(decl: Declaration): string {
354
354
return decl . text
355
355
}
356
356
357
+ /**
358
+ * Check if a type annotation is a generic/broad type that should be replaced with narrow inference
359
+ */
360
+ function isGenericType ( typeAnnotation : string ) : boolean {
361
+ const trimmed = typeAnnotation . trim ( )
362
+
363
+ // Generic types that are less specific than narrow inference
364
+ if ( trimmed === 'any' || trimmed === 'object' || trimmed === 'unknown' ) {
365
+ return true
366
+ }
367
+
368
+ // Record types like Record<string, string>, Record<string, any>, etc.
369
+ if ( trimmed . startsWith ( 'Record<' ) && trimmed . endsWith ( '>' ) ) {
370
+ return true
371
+ }
372
+
373
+ // Array types like Array<any>, Array<string>, etc. (but not specific tuples)
374
+ if ( trimmed . startsWith ( 'Array<' ) && trimmed . endsWith ( '>' ) ) {
375
+ return true
376
+ }
377
+
378
+ // Object types like { [key: string]: any }
379
+ if ( trimmed . match ( / ^ \{ \s * \[ .* \] : \s * ( a n y | s t r i n g | n u m b e r | u n k n o w n ) \s * \} $ / ) ) {
380
+ return true
381
+ }
382
+
383
+ return false
384
+ }
385
+
357
386
/**
358
387
* Process variable declaration to DTS format
359
388
*/
@@ -1135,7 +1164,7 @@ function parseObjectProperties(content: string): Array<[string, string]> {
1135
1164
inKey = false
1136
1165
depth = 1 // We're now inside the method definition
1137
1166
} else if ( char === ',' && depth === 0 ) {
1138
- if ( currentKey && current . trim ( ) ) {
1167
+ if ( currentKey && current . trim ( ) ) {
1139
1168
// Clean method signatures before storing
1140
1169
let value = current . trim ( )
1141
1170
@@ -1236,6 +1265,51 @@ function findMatchingBracket(str: string, start: number, openChar: string, close
1236
1265
return - 1
1237
1266
}
1238
1267
1268
+ /**
1269
+ * Find the main arrow (=>) in a function, ignoring nested arrows in parameter types
1270
+ */
1271
+ function findMainArrowIndex ( str : string ) : number {
1272
+ let parenDepth = 0
1273
+ let bracketDepth = 0
1274
+ let inString = false
1275
+ let stringChar = ''
1276
+
1277
+ for ( let i = 0 ; i < str . length - 1 ; i ++ ) {
1278
+ const char = str [ i ]
1279
+ const nextChar = str [ i + 1 ]
1280
+ const prevChar = i > 0 ? str [ i - 1 ] : ''
1281
+
1282
+ // Handle string literals
1283
+ if ( ! inString && ( char === '"' || char === "'" || char === '`' ) ) {
1284
+ inString = true
1285
+ stringChar = char
1286
+ } else if ( inString && char === stringChar && prevChar !== '\\' ) {
1287
+ inString = false
1288
+ }
1289
+
1290
+ if ( ! inString ) {
1291
+ // Track nesting depth - only parentheses and square brackets
1292
+ // Don't track < > as they can be comparison operators or part of generics
1293
+ if ( char === '(' ) {
1294
+ parenDepth ++
1295
+ } else if ( char === ')' ) {
1296
+ parenDepth --
1297
+ } else if ( char === '[' ) {
1298
+ bracketDepth ++
1299
+ } else if ( char === ']' ) {
1300
+ bracketDepth --
1301
+ }
1302
+
1303
+ // Look for arrow at depth 0 (not nested inside parentheses or brackets)
1304
+ if ( char === '=' && nextChar === '>' && parenDepth === 0 && bracketDepth === 0 ) {
1305
+ return i
1306
+ }
1307
+ }
1308
+ }
1309
+
1310
+ return - 1
1311
+ }
1312
+
1239
1313
/**
1240
1314
* Infer function type from function expression
1241
1315
*/
@@ -1297,7 +1371,8 @@ function inferFunctionType(value: string, inUnion: boolean = false): string {
1297
1371
}
1298
1372
}
1299
1373
1300
- const arrowIndex = remaining . indexOf ( '=>' )
1374
+ // Find the main arrow (not nested ones inside parameter types)
1375
+ const arrowIndex = findMainArrowIndex ( remaining )
1301
1376
if ( arrowIndex === - 1 ) {
1302
1377
// Fallback if no arrow found
1303
1378
const funcType = '() => unknown'
@@ -1337,9 +1412,20 @@ function inferFunctionType(value: string, inUnion: boolean = false): string {
1337
1412
returnType = 'unknown'
1338
1413
} else if ( body . includes ( '=>' ) ) {
1339
1414
// This is a higher-order function returning another function
1340
- // Try to infer the return function type
1341
- const innerFuncType = inferFunctionType ( body , false )
1342
- returnType = innerFuncType
1415
+ // For complex nested functions, try to extract just the outer function signature
1416
+ const outerFuncMatch = body . match ( / ^ \s * \( ( [ ^ ) ] * ) \) \s * = > / ) ;
1417
+ if ( outerFuncMatch ) {
1418
+ const outerParams = outerFuncMatch [ 1 ] . trim ( ) ;
1419
+ // For functions like pipe that transform T => T, infer the return type from generics
1420
+ if ( generics . includes ( 'T' ) && outerParams . includes ( 'T' ) ) {
1421
+ returnType = `(${ outerParams } ) => T` ;
1422
+ } else {
1423
+ returnType = `(${ outerParams } ) => any` ;
1424
+ }
1425
+ } else {
1426
+ // Fallback for complex cases
1427
+ returnType = 'any' ;
1428
+ }
1343
1429
} else {
1344
1430
// Expression body - try to infer, but be conservative in union contexts
1345
1431
if ( inUnion ) {
0 commit comments