Skip to content

Commit 7890fd5

Browse files
authored
Merge pull request microsoft#9088 from Microsoft/add-members-to-variable-declarations-initialised-with-function-expressions
Add members to variable declarations initialised with function expressions
2 parents 57f66b8 + 4a9b120 commit 7890fd5

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

src/compiler/binder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1961,7 +1961,7 @@ namespace ts {
19611961
classPrototype.parent = leftSideOfAssignment;
19621962

19631963
const funcSymbol = container.locals[constructorFunction.text];
1964-
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function)) {
1964+
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) {
19651965
return;
19661966
}
19671967

src/compiler/checker.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -11495,8 +11495,12 @@ namespace ts {
1149511495
// When resolved signature is a call signature (and not a construct signature) the result type is any, unless
1149611496
// the declaring function had members created through 'x.prototype.y = expr' or 'this.y = expr' psuedodeclarations
1149711497
// in a JS file
11498-
const funcSymbol = checkExpression(node.expression).symbol;
11499-
if (funcSymbol && funcSymbol.members && (funcSymbol.flags & SymbolFlags.Function)) {
11498+
// Note:JS inferred classes might come from a variable declaration instead of a function declaration.
11499+
// In this case, using getResolvedSymbol directly is required to avoid losing the members from the declaration.
11500+
const funcSymbol = node.expression.kind === SyntaxKind.Identifier ?
11501+
getResolvedSymbol(node.expression as Identifier) :
11502+
checkExpression(node.expression).symbol;
11503+
if (funcSymbol && funcSymbol.members && (funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) {
1150011504
return getInferredClassType(funcSymbol);
1150111505
}
1150211506
else if (compilerOptions.noImplicitAny) {

src/compiler/utilities.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,18 @@ namespace ts {
12641264
return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote;
12651265
}
12661266

1267+
/**
1268+
* Returns true if the node is a variable declaration whose initializer is a function expression.
1269+
* This function does not test if the node is in a JavaScript file or not.
1270+
*/
1271+
export function isDeclarationOfFunctionExpression(s: Symbol) {
1272+
if (s.valueDeclaration && s.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
1273+
const declaration = s.valueDeclaration as VariableDeclaration;
1274+
return declaration.initializer && declaration.initializer.kind === SyntaxKind.FunctionExpression;
1275+
}
1276+
return false;
1277+
}
1278+
12671279
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
12681280
/// assignments we treat as special in the binder
12691281
export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference path="fourslash.ts" />
2+
// @allowJs: true
3+
// @Filename: something.js
4+
////var C = function () { }
5+
/////**
6+
//// * The prototype method.
7+
//// * @param {string} a Parameter definition.
8+
//// */
9+
////function f(a) {}
10+
////C.prototype.m = f;
11+
////
12+
////var x = new C();
13+
////x/*1*/./*2*/m();
14+
goTo.marker('1');
15+
verify.quickInfoIs('var x: {\n m: (a: string) => void;\n}');
16+
goTo.marker('2');
17+
verify.completionListContains('m', '(property) C.m: (a: string) => void', 'The prototype method.');

0 commit comments

Comments
 (0)