Skip to content

Commit dca3a94

Browse files
authored
Print js-constructor function type names (microsoft#23089)
* Print js-constructor function type names Instead of printing them as a type literal, which is scary. * Use assigned name for functions and classes That otherwise have no name. This helps quick info for javascript a *lot*. Typescript mainly benefits when printing the type of class expressions. * Improve names of functions in binding elements Also fix some fourslash baselines
1 parent 9b987eb commit dca3a94

57 files changed

Lines changed: 1194 additions & 577 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/compiler/checker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3069,8 +3069,13 @@ namespace ts {
30693069
function createAnonymousTypeNode(type: ObjectType): TypeNode {
30703070
const symbol = type.symbol;
30713071
if (symbol) {
3072+
if (isJavaScriptConstructor(symbol.valueDeclaration)) {
3073+
// Instance and static types share the same symbol; only add 'typeof' for the static side.
3074+
const isInstanceType = type === getInferredClassType(symbol) ? SymbolFlags.Type : SymbolFlags.Value;
3075+
return symbolToTypeNode(symbol, context, isInstanceType);
3076+
}
30723077
// Always use 'typeof T' for type of class, enum, and module objects
3073-
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) && !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) ||
3078+
else if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) && !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) ||
30743079
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
30753080
shouldWriteTypeOfFunctionSymbol()) {
30763081
return symbolToTypeNode(symbol, context, SymbolFlags.Value);

src/compiler/utilities.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4552,6 +4552,12 @@ namespace ts {
45524552
return undefined;
45534553
}
45544554
switch (declaration.kind) {
4555+
case SyntaxKind.ClassExpression:
4556+
case SyntaxKind.FunctionExpression:
4557+
if (!(declaration as ClassExpression | FunctionExpression).name) {
4558+
return getAssignedName(declaration);
4559+
}
4560+
break;
45554561
case SyntaxKind.Identifier:
45564562
return declaration as Identifier;
45574563
case SyntaxKind.JSDocPropertyTag:
@@ -4584,6 +4590,23 @@ namespace ts {
45844590
return (declaration as NamedDeclaration).name;
45854591
}
45864592

4593+
function getAssignedName(node: Node): DeclarationName {
4594+
if (!node.parent) {
4595+
return undefined;
4596+
}
4597+
else if (isPropertyAssignment(node.parent) || isBindingElement(node.parent)) {
4598+
return node.parent.name;
4599+
}
4600+
else if (isBinaryExpression(node.parent) && node === node.parent.right) {
4601+
if (isIdentifier(node.parent.left)) {
4602+
return node.parent.left;
4603+
}
4604+
else if (isPropertyAccessExpression(node.parent.left)) {
4605+
return node.parent.left.name;
4606+
}
4607+
}
4608+
}
4609+
45874610
/**
45884611
* Gets the JSDoc parameter tags for the node if present.
45894612
*

tests/baselines/reference/chainedPrototypeAssignment.types

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,30 @@ var mod = require('./mod');
77
>'./mod' : "./mod"
88

99
var a = new mod.A()
10-
>a : { a: number; } & { [x: string]: any; m(n: number): number; }
11-
>new mod.A() : { a: number; } & { [x: string]: any; m(n: number): number; }
12-
>mod.A : () => void
10+
>a : A & { [x: string]: any; m(n: number): number; }
11+
>new mod.A() : A & { [x: string]: any; m(n: number): number; }
12+
>mod.A : typeof A
1313
>mod : typeof import("tests/cases/conformance/salsa/mod")
14-
>A : () => void
14+
>A : typeof A
1515

1616
var b = new mod.B()
17-
>b : { b: number; } & { [x: string]: any; m(n: number): number; }
18-
>new mod.B() : { b: number; } & { [x: string]: any; m(n: number): number; }
19-
>mod.B : () => void
17+
>b : B & { [x: string]: any; m(n: number): number; }
18+
>new mod.B() : B & { [x: string]: any; m(n: number): number; }
19+
>mod.B : typeof B
2020
>mod : typeof import("tests/cases/conformance/salsa/mod")
21-
>B : () => void
21+
>B : typeof B
2222

2323
a.m('nope')
2424
>a.m('nope') : number
2525
>a.m : (n: number) => number
26-
>a : { a: number; } & { [x: string]: any; m(n: number): number; }
26+
>a : A & { [x: string]: any; m(n: number): number; }
2727
>m : (n: number) => number
2828
>'nope' : "nope"
2929

3030
b.m('not really')
3131
>b.m('not really') : number
3232
>b.m : (n: number) => number
33-
>b : { b: number; } & { [x: string]: any; m(n: number): number; }
33+
>b : B & { [x: string]: any; m(n: number): number; }
3434
>m : (n: number) => number
3535
>'not really' : "not really"
3636

@@ -45,8 +45,8 @@ declare var exports: any;
4545
=== tests/cases/conformance/salsa/mod.js ===
4646
/// <reference path='./types.d.ts'/>
4747
var A = function() {
48-
>A : () => void
49-
>function() { this.a = 1} : () => void
48+
>A : typeof A
49+
>function() { this.a = 1} : typeof A
5050

5151
this.a = 1
5252
>this.a = 1 : 1
@@ -56,8 +56,8 @@ var A = function() {
5656
>1 : 1
5757
}
5858
var B = function() {
59-
>B : () => void
60-
>function() { this.b = 2} : () => void
59+
>B : typeof B
60+
>function() { this.b = 2} : typeof B
6161

6262
this.b = 2
6363
>this.b = 2 : 2
@@ -67,27 +67,27 @@ var B = function() {
6767
>2 : 2
6868
}
6969
exports.A = A
70-
>exports.A = A : () => void
71-
>exports.A : () => void
70+
>exports.A = A : typeof A
71+
>exports.A : typeof A
7272
>exports : typeof import("tests/cases/conformance/salsa/mod")
73-
>A : () => void
74-
>A : () => void
73+
>A : typeof A
74+
>A : typeof A
7575

7676
exports.B = B
77-
>exports.B = B : () => void
78-
>exports.B : () => void
77+
>exports.B = B : typeof B
78+
>exports.B : typeof B
7979
>exports : typeof import("tests/cases/conformance/salsa/mod")
80-
>B : () => void
81-
>B : () => void
80+
>B : typeof B
81+
>B : typeof B
8282

8383
A.prototype = B.prototype = {
8484
>A.prototype = B.prototype = { /** @param {number} n */ m(n) { return n + 1 }} : { [x: string]: any; m(n: number): number; }
8585
>A.prototype : any
86-
>A : () => void
86+
>A : typeof A
8787
>prototype : any
8888
>B.prototype = { /** @param {number} n */ m(n) { return n + 1 }} : { [x: string]: any; m(n: number): number; }
8989
>B.prototype : any
90-
>B : () => void
90+
>B : typeof B
9191
>prototype : any
9292
>{ /** @param {number} n */ m(n) { return n + 1 }} : { [x: string]: any; m(n: number): number; }
9393

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/ts.ts ===
2+
var o = {
3+
>o : Symbol(o, Decl(ts.ts, 0, 3))
4+
5+
C: class {
6+
>C : Symbol(C, Decl(ts.ts, 0, 9))
7+
}
8+
}
9+
var oc = new o.C()
10+
>oc : Symbol(oc, Decl(ts.ts, 4, 3))
11+
>o.C : Symbol(C, Decl(ts.ts, 0, 9))
12+
>o : Symbol(o, Decl(ts.ts, 0, 3))
13+
>C : Symbol(C, Decl(ts.ts, 0, 9))
14+
15+
var V = class {
16+
>V : Symbol(V, Decl(ts.ts, 6, 3))
17+
}
18+
var v = new V()
19+
>v : Symbol(v, Decl(ts.ts, 8, 3))
20+
>V : Symbol(V, Decl(ts.ts, 6, 3))
21+
22+
var A;
23+
>A : Symbol(A, Decl(ts.ts, 10, 3))
24+
25+
A = class {
26+
>A : Symbol(A, Decl(ts.ts, 10, 3))
27+
}
28+
var a = new A()
29+
>a : Symbol(a, Decl(ts.ts, 13, 3))
30+
>A : Symbol(A, Decl(ts.ts, 10, 3))
31+
32+
const {
33+
B = class { }
34+
>B : Symbol(B, Decl(ts.ts, 15, 7))
35+
36+
} = ({ B: undefined });
37+
>B : Symbol(B, Decl(ts.ts, 17, 6))
38+
>undefined : Symbol(undefined)
39+
40+
var b = new B();
41+
>b : Symbol(b, Decl(ts.ts, 18, 3))
42+
>B : Symbol(B, Decl(ts.ts, 15, 7))
43+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
=== tests/cases/compiler/ts.ts ===
2+
var o = {
3+
>o : { C: typeof C; }
4+
>{ C: class { }} : { C: typeof C; }
5+
6+
C: class {
7+
>C : typeof C
8+
>class { } : typeof C
9+
}
10+
}
11+
var oc = new o.C()
12+
>oc : C
13+
>new o.C() : C
14+
>o.C : typeof C
15+
>o : { C: typeof C; }
16+
>C : typeof C
17+
18+
var V = class {
19+
>V : typeof V
20+
>class {} : typeof V
21+
}
22+
var v = new V()
23+
>v : V
24+
>new V() : V
25+
>V : typeof V
26+
27+
var A;
28+
>A : any
29+
30+
A = class {
31+
>A = class {} : typeof A
32+
>A : any
33+
>class {} : typeof A
34+
}
35+
var a = new A()
36+
>a : A
37+
>new A() : A
38+
>A : typeof A
39+
40+
const {
41+
B = class { }
42+
>B : typeof B
43+
>class { } : typeof B
44+
45+
} = ({ B: undefined });
46+
>({ B: undefined }) : { B?: undefined; }
47+
>{ B: undefined } : { B?: undefined; }
48+
>B : undefined
49+
>undefined : undefined
50+
51+
var b = new B();
52+
>b : B
53+
>new B() : B
54+
>B : typeof B
55+

tests/baselines/reference/commonjsAccessExports.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ exports.x;
1818
>Cls : Symbol(Cls, Decl(a.js, 4, 1))
1919

2020
this.x = 0;
21-
>x : Symbol((Anonymous function).x, Decl(a.js, 6, 30))
21+
>x : Symbol(Cls.x, Decl(a.js, 6, 30))
2222
}
2323
}
2424

tests/baselines/reference/commonjsAccessExports.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ exports.x;
1515
{
1616
// 'exports' does not provide a contextual type to a function-class
1717
exports.Cls = function() {
18-
>exports.Cls = function() { this.x = 0; } : () => void
19-
>exports.Cls : () => void
18+
>exports.Cls = function() { this.x = 0; } : typeof Cls
19+
>exports.Cls : typeof Cls
2020
>exports : typeof import("/a")
21-
>Cls : () => void
22-
>function() { this.x = 0; } : () => void
21+
>Cls : typeof Cls
22+
>function() { this.x = 0; } : typeof Cls
2323

2424
this.x = 0;
2525
>this.x = 0 : 0
@@ -31,9 +31,9 @@ exports.x;
3131
}
3232

3333
const instance = new exports.Cls();
34-
>instance : { x: number; }
35-
>new exports.Cls() : { x: number; }
36-
>exports.Cls : () => void
34+
>instance : Cls
35+
>new exports.Cls() : Cls
36+
>exports.Cls : typeof Cls
3737
>exports : typeof import("/a")
38-
>Cls : () => void
38+
>Cls : typeof Cls
3939

0 commit comments

Comments
 (0)