Skip to content

Commit d3e0929

Browse files
authored
Mark js-assignment functions' symbols as methods (#23078)
This make display more accurate: 1. The functions now print as methods 2. When the type of the function references the class, the type of the function itself is now printed correctly instead of as `any`.
1 parent 72e92a0 commit d3e0929

22 files changed

+171
-166
lines changed

src/compiler/binder.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,8 +2473,10 @@ namespace ts {
24732473
(symbol.exports || (symbol.exports = createSymbolTable()));
24742474

24752475
// Declare the method/property
2476-
const symbolFlags = SymbolFlags.Property | (isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
2477-
const symbolExcludes = SymbolFlags.PropertyExcludes & ~(isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
2476+
const jsContainerFlag = isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0;
2477+
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess));
2478+
const symbolFlags = (isMethod ? SymbolFlags.Method : SymbolFlags.Property) | jsContainerFlag;
2479+
const symbolExcludes = (isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes) & ~jsContainerFlag;
24782480
declareSymbol(symbolTable, symbol, propertyAccess, symbolFlags, symbolExcludes);
24792481
}
24802482

src/compiler/checker.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4679,6 +4679,10 @@ namespace ts {
46794679
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
46804680
links.type = anyType;
46814681
}
4682+
else if (symbol.valueDeclaration.kind === SyntaxKind.BinaryExpression ||
4683+
symbol.valueDeclaration.kind === SyntaxKind.PropertyAccessExpression && symbol.valueDeclaration.parent.kind === SyntaxKind.BinaryExpression) {
4684+
links.type = getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
4685+
}
46824686
else {
46834687
const type = createObjectType(ObjectFlags.Anonymous, symbol);
46844688
if (symbol.flags & SymbolFlags.Class) {
@@ -6935,7 +6939,8 @@ namespace ts {
69356939
if (!symbol) return emptyArray;
69366940
const result: Signature[] = [];
69376941
for (let i = 0; i < symbol.declarations.length; i++) {
6938-
const node = symbol.declarations[i];
6942+
const decl = symbol.declarations[i];
6943+
const node = isPropertyAccessExpression(decl) ? getAssignedJavascriptInitializer(decl) : decl;
69396944
if (!isFunctionLike(node)) continue;
69406945
// Don't include signature if node is the implementation of an overloaded function. A node is considered
69416946
// an implementation node if it has a body and the previous node is of the same kind and immediately
@@ -16221,9 +16226,7 @@ namespace ts {
1622116226
}
1622216227

1622316228
function isMethodLike(symbol: Symbol) {
16224-
return !!(symbol.flags & SymbolFlags.Method ||
16225-
getCheckFlags(symbol) & CheckFlags.SyntheticMethod ||
16226-
isInJavaScriptFile(symbol.valueDeclaration) && isFunctionLikeDeclaration(getAssignedJavascriptInitializer(symbol.valueDeclaration)));
16229+
return !!(symbol.flags & SymbolFlags.Method || getCheckFlags(symbol) & CheckFlags.SyntheticMethod);
1622716230
}
1622816231

1622916232
/**

src/services/codefixes/convertFunctionToEs6Class.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ namespace ts.codefix {
9999
}
100100

101101
function createClassElement(symbol: Symbol, modifiers: Modifier[]): ClassElement {
102-
// both properties and methods are bound as property symbols
103-
if (!(symbol.flags & SymbolFlags.Property)) {
102+
// Right now the only thing we can convert are function expressions, which are marked as methods
103+
if (!(symbol.flags & SymbolFlags.Method)) {
104104
return;
105105
}
106106

tests/baselines/reference/constructorFunctions2.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,23 @@ B.prototype.m = function() { this.x = 2; }
4040
>function() { this.x = 2; } : () => void
4141
>this.x = 2 : 2
4242
>this.x : number
43-
>this : { id: number; m: () => void; x: number; }
43+
>this : { id: number; m(): void; x: number; }
4444
>x : number
4545
>2 : 2
4646

4747
const b = new B();
48-
>b : { id: number; m: () => void; x: number; }
49-
>new B() : { id: number; m: () => void; x: number; }
48+
>b : { id: number; m(): void; x: number; }
49+
>new B() : { id: number; m(): void; x: number; }
5050
>B : () => void
5151

5252
b.id;
5353
>b.id : number
54-
>b : { id: number; m: () => void; x: number; }
54+
>b : { id: number; m(): void; x: number; }
5555
>id : number
5656

5757
b.x;
5858
>b.x : number
59-
>b : { id: number; m: () => void; x: number; }
59+
>b : { id: number; m(): void; x: number; }
6060
>x : number
6161

6262
=== tests/cases/conformance/salsa/other.js ===

tests/baselines/reference/constructorFunctionsStrict.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,27 @@ C.prototype.m = function() {
2323
this.y = 12
2424
>this.y = 12 : 12
2525
>this.y : number | undefined
26-
>this : { x: number; m: () => void; y: number | undefined; }
26+
>this : { x: number; m(): void; y: number | undefined; }
2727
>y : number | undefined
2828
>12 : 12
2929
}
3030
var c = new C(1)
31-
>c : { x: number; m: () => void; y: number | undefined; }
32-
>new C(1) : { x: number; m: () => void; y: number | undefined; }
31+
>c : { x: number; m(): void; y: number | undefined; }
32+
>new C(1) : { x: number; m(): void; y: number | undefined; }
3333
>C : (x: number) => void
3434
>1 : 1
3535

3636
c.x = undefined // should error
3737
>c.x = undefined : undefined
3838
>c.x : number
39-
>c : { x: number; m: () => void; y: number | undefined; }
39+
>c : { x: number; m(): void; y: number | undefined; }
4040
>x : number
4141
>undefined : undefined
4242

4343
c.y = undefined // ok
4444
>c.y = undefined : undefined
4545
>c.y : number | undefined
46-
>c : { x: number; m: () => void; y: number | undefined; }
46+
>c : { x: number; m(): void; y: number | undefined; }
4747
>y : number | undefined
4848
>undefined : undefined
4949

tests/baselines/reference/inferringClassMembersFromAssignments2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ OOOrder.prototype.m = function () {
1111
this.p = 1
1212
>this.p = 1 : 1
1313
>this.p : number
14-
>this : { x: number; m: () => void; p: number; }
14+
>this : { x: number; m(): void; p: number; }
1515
>p : number
1616
>1 : 1
1717
}

tests/baselines/reference/jsContainerMergeTsDeclaration.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
=== tests/cases/conformance/salsa/a.js ===
22
var /*1*/x = function foo() {
3-
>x : { (): void; a: () => void; }
4-
>function foo() {} : { (): void; a: () => void; }
5-
>foo : { (): void; a: () => void; }
3+
>x : { (): void; a(): void; }
4+
>function foo() {} : { (): void; a(): void; }
5+
>foo : { (): void; a(): void; }
66
}
77
x.a = function bar() {
88
>x.a = function bar() {} : () => void
99
>x.a : () => void
10-
>x : { (): void; a: () => void; }
10+
>x : { (): void; a(): void; }
1111
>a : () => void
1212
>function bar() {} : () => void
1313
>bar : () => void
1414
}
1515
=== tests/cases/conformance/salsa/b.ts ===
1616
var x = function () {
17-
>x : { (): void; a: () => void; }
17+
>x : { (): void; a(): void; }
1818
>function () { return 1;}() : number
1919
>function () { return 1;} : () => number
2020

0 commit comments

Comments
 (0)