@@ -383,6 +383,70 @@ export class TSHelper {
383383 param => ts . isIdentifier ( param . name ) && param . name . originalKeywordKind === ts . SyntaxKind . ThisKeyword ) ;
384384 }
385385
386+ public static inferAssignedType ( expression : ts . Expression , checker : ts . TypeChecker ) : ts . Type {
387+ if ( ts . isParenthesizedExpression ( expression . parent ) ) {
388+ // Ignore expressions wrapped in parenthesis
389+ return this . inferAssignedType ( expression . parent , checker ) ;
390+
391+ } else if ( ts . isCallExpression ( expression . parent ) ) {
392+ // Expression being passed as argument to a function
393+ let i = expression . parent . arguments . indexOf ( expression ) ;
394+ if ( i >= 0 ) {
395+ const parentSignature = checker . getResolvedSignature ( expression . parent ) ;
396+ const parentSignatureDeclaration = parentSignature . getDeclaration ( ) ;
397+ if ( parentSignatureDeclaration ) {
398+ if ( this . getExplicitThisParameter ( parentSignatureDeclaration ) ) {
399+ ++ i ;
400+ }
401+ return checker . getTypeAtLocation ( parentSignatureDeclaration . parameters [ i ] ) ;
402+ }
403+ }
404+
405+ } else if ( ts . isReturnStatement ( expression . parent ) ) {
406+ // Expression being returned from a function
407+ return this . getContainingFunctionReturnType ( expression . parent , checker ) ;
408+
409+ } else if ( ts . isPropertyDeclaration ( expression . parent ) ) {
410+ // Expression being assigned to a class property
411+ return checker . getTypeAtLocation ( expression . parent ) ;
412+
413+ } else if ( ts . isPropertyAssignment ( expression . parent ) ) {
414+ // Expression being assigned to an object literal property
415+ const objType = this . inferAssignedType ( expression . parent . parent , checker ) ;
416+ const property = objType . getProperty ( expression . parent . name . getText ( ) ) ;
417+ if ( ! property ) {
418+ return objType . getStringIndexType ( ) ;
419+ } else {
420+ return checker . getTypeAtLocation ( property . valueDeclaration ) ;
421+ }
422+
423+ } else if ( ts . isArrayLiteralExpression ( expression . parent ) ) {
424+ // Expression in an array literal
425+ const arrayType = this . inferAssignedType ( expression . parent , checker ) ;
426+ if ( ts . isTupleTypeNode ( checker . typeToTypeNode ( arrayType ) ) ) {
427+ // Tuples
428+ const i = expression . parent . elements . indexOf ( expression ) ;
429+ const elementType = ( arrayType as ts . TypeReference ) . typeArguments [ i ] ;
430+ return elementType ;
431+ } else {
432+ // Standard arrays
433+ return arrayType . getNumberIndexType ( ) ;
434+ }
435+
436+ } else if ( ts . isVariableDeclaration ( expression . parent ) ) {
437+ // Expression assigned to declaration
438+ return checker . getTypeAtLocation ( expression . parent . name ) ;
439+
440+ } else if ( ts . isBinaryExpression ( expression . parent )
441+ && expression . parent . operatorToken . kind === ts . SyntaxKind . EqualsToken )
442+ {
443+ // Expression assigned to variable
444+ return checker . getTypeAtLocation ( expression . parent . left ) ;
445+ }
446+
447+ return checker . getTypeAtLocation ( expression ) ;
448+ }
449+
386450 public static getSignatureDeclarations (
387451 signatures : ts . Signature [ ] ,
388452 checker : ts . TypeChecker
@@ -392,29 +456,14 @@ export class TSHelper {
392456 for ( const signature of signatures ) {
393457 const signatureDeclaration = signature . getDeclaration ( ) ;
394458 if ( ( ts . isFunctionExpression ( signatureDeclaration ) || ts . isArrowFunction ( signatureDeclaration ) )
395- && ! this . getExplicitThisParameter ( signatureDeclaration ) ) {
396- // Function expressions: get signatures of type being assigned to, unless 'this' was explicit
397- let declType : ts . Type ;
398- if ( ts . isCallExpression ( signatureDeclaration . parent ) ) {
399- // Function expression being passed as argument to another function
400- const i = signatureDeclaration . parent . arguments . indexOf ( signatureDeclaration ) ;
401- if ( i >= 0 ) {
402- const parentSignature = checker . getResolvedSignature ( signatureDeclaration . parent ) ;
403- const parentSignatureDeclaration = parentSignature . getDeclaration ( ) ;
404- if ( parentSignatureDeclaration ) {
405- declType = checker . getTypeAtLocation ( parentSignatureDeclaration . parameters [ i ] ) ;
406- }
407- }
408- } else if ( ts . isReturnStatement ( signatureDeclaration . parent ) ) {
409- declType = this . getContainingFunctionReturnType ( signatureDeclaration . parent , checker ) ;
410- } else {
411- // Function expression being assigned
412- declType = checker . getTypeAtLocation ( signatureDeclaration . parent ) ;
413- }
414- if ( declType ) {
415- const declSignatures = declType . getCallSignatures ( ) ;
416- if ( declSignatures . length > 0 ) {
417- declSignatures . map ( s => s . getDeclaration ( ) ) . forEach ( decl => signatureDeclarations . push ( decl ) ) ;
459+ && ! this . getExplicitThisParameter ( signatureDeclaration ) )
460+ {
461+ // Infer type of function expressions/arrow functions
462+ const inferredType = this . inferAssignedType ( signatureDeclaration , checker ) ;
463+ if ( inferredType ) {
464+ const inferredSignatures = inferredType . getCallSignatures ( ) ;
465+ if ( inferredSignatures . length > 0 ) {
466+ signatureDeclarations . push ( ...inferredSignatures . map ( s => s . getDeclaration ( ) ) ) ;
418467 continue ;
419468 }
420469 }
0 commit comments