Skip to content

Commit d9f0212

Browse files
authored
Resolve SymbolFlags.Type only at first in jsdoc getTypeFromTypeReference (#32947)
* Fix lookup of exported eunm type alias in local scope in JS * Fix by adjusting type lookup fallback behavior to not include SymbolFlags.Value in its initial lookup instead
1 parent 2cde3b7 commit d9f0212

File tree

7 files changed

+248
-7
lines changed

7 files changed

+248
-7
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9165,12 +9165,12 @@ namespace ts {
91659165
return undefined;
91669166
}
91679167

9168-
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName | undefined, meaning: SymbolFlags) {
9168+
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName | undefined, meaning: SymbolFlags, ignoreErrors?: boolean) {
91699169
if (!typeReferenceName) {
91709170
return unknownSymbol;
91719171
}
91729172

9173-
return resolveEntityName(typeReferenceName, meaning) || unknownSymbol;
9173+
return resolveEntityName(typeReferenceName, meaning, ignoreErrors) || unknownSymbol;
91749174
}
91759175

91769176
function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type {
@@ -9362,10 +9362,19 @@ namespace ts {
93629362
if (!links.resolvedType) {
93639363
let symbol: Symbol | undefined;
93649364
let type: Type | undefined;
9365-
let meaning = SymbolFlags.Type;
9365+
const meaning = SymbolFlags.Type;
93669366
if (isJSDocTypeReference(node)) {
93679367
type = getIntendedTypeFromJSDocTypeReference(node);
9368-
meaning |= SymbolFlags.Value;
9368+
if (!type) {
9369+
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning, /*ignoreErrors*/ true);
9370+
if (symbol === unknownSymbol) {
9371+
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning | SymbolFlags.Value);
9372+
}
9373+
else {
9374+
resolveTypeReferenceName(getTypeReferenceName(node), meaning); // Resolve again to mark errors, if any
9375+
}
9376+
type = getTypeReferenceType(node, symbol);
9377+
}
93699378
}
93709379
if (!type) {
93719380
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning);
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
=== tests/cases/compiler/usage.js ===
2+
const { Thing, useThing, cbThing } = require("./index");
3+
>Thing : Symbol(Thing, Decl(usage.js, 0, 7))
4+
>useThing : Symbol(useThing, Decl(usage.js, 0, 14))
5+
>cbThing : Symbol(cbThing, Decl(usage.js, 0, 24))
6+
>require : Symbol(require)
7+
>"./index" : Symbol("tests/cases/compiler/index", Decl(index.js, 0, 0))
8+
9+
useThing(Thing.a);
10+
>useThing : Symbol(useThing, Decl(usage.js, 0, 14))
11+
>Thing : Symbol(Thing, Decl(usage.js, 0, 7))
12+
13+
/**
14+
* @typedef {Object} LogEntry
15+
* @property {string} type
16+
* @property {number} time
17+
*/
18+
19+
cbThing(type => {
20+
>cbThing : Symbol(cbThing, Decl(usage.js, 0, 24))
21+
>type : Symbol(type, Decl(usage.js, 10, 8))
22+
23+
/** @type {LogEntry} */
24+
const logEntry = {
25+
>logEntry : Symbol(logEntry, Decl(usage.js, 12, 9))
26+
27+
time: Date.now(),
28+
>time : Symbol(time, Decl(usage.js, 12, 22))
29+
>Date.now : Symbol(DateConstructor.now, Decl(lib.es5.d.ts, --, --))
30+
>Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --))
31+
>now : Symbol(DateConstructor.now, Decl(lib.es5.d.ts, --, --))
32+
33+
type,
34+
>type : Symbol(type, Decl(usage.js, 13, 25))
35+
36+
};
37+
});
38+
39+
=== tests/cases/compiler/index.js ===
40+
/** @enum {string} */
41+
const Thing = Object.freeze({
42+
>Thing : Symbol(Thing, Decl(index.js, 1, 5), Decl(index.js, 0, 4))
43+
>Object.freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
44+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
45+
>freeze : Symbol(ObjectConstructor.freeze, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
46+
47+
a: "thing",
48+
>a : Symbol(a, Decl(index.js, 1, 29))
49+
50+
b: "chill"
51+
>b : Symbol(b, Decl(index.js, 2, 15))
52+
53+
});
54+
55+
exports.Thing = Thing;
56+
>exports.Thing : Symbol(Thing, Decl(index.js, 4, 3), Decl(index.js, 0, 4))
57+
>exports : Symbol(Thing, Decl(index.js, 4, 3), Decl(index.js, 0, 4))
58+
>Thing : Symbol(Thing, Decl(index.js, 4, 3), Decl(index.js, 0, 4))
59+
>Thing : Symbol(Thing, Decl(index.js, 1, 5), Decl(index.js, 0, 4))
60+
61+
/**
62+
* @param {Thing} x
63+
*/
64+
function useThing(x) {}
65+
>useThing : Symbol(useThing, Decl(index.js, 6, 22))
66+
>x : Symbol(x, Decl(index.js, 11, 18))
67+
68+
exports.useThing = useThing;
69+
>exports.useThing : Symbol(useThing, Decl(index.js, 11, 23))
70+
>exports : Symbol(useThing, Decl(index.js, 11, 23))
71+
>useThing : Symbol(useThing, Decl(index.js, 11, 23))
72+
>useThing : Symbol(useThing, Decl(index.js, 6, 22))
73+
74+
/**
75+
* @param {(x: Thing) => void} x
76+
*/
77+
function cbThing(x) {}
78+
>cbThing : Symbol(cbThing, Decl(index.js, 13, 28))
79+
>x : Symbol(x, Decl(index.js, 18, 17))
80+
81+
exports.cbThing = cbThing;
82+
>exports.cbThing : Symbol(cbThing, Decl(index.js, 18, 22))
83+
>exports : Symbol(cbThing, Decl(index.js, 18, 22))
84+
>cbThing : Symbol(cbThing, Decl(index.js, 18, 22))
85+
>cbThing : Symbol(cbThing, Decl(index.js, 13, 28))
86+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
=== tests/cases/compiler/usage.js ===
2+
const { Thing, useThing, cbThing } = require("./index");
3+
>Thing : any
4+
>useThing : (x: string) => void
5+
>cbThing : (x: (x: string) => void) => void
6+
>require("./index") : typeof import("tests/cases/compiler/index")
7+
>require : any
8+
>"./index" : "./index"
9+
10+
useThing(Thing.a);
11+
>useThing(Thing.a) : void
12+
>useThing : (x: string) => void
13+
>Thing.a : error
14+
>Thing : any
15+
>a : any
16+
17+
/**
18+
* @typedef {Object} LogEntry
19+
* @property {string} type
20+
* @property {number} time
21+
*/
22+
23+
cbThing(type => {
24+
>cbThing(type => { /** @type {LogEntry} */ const logEntry = { time: Date.now(), type, };}) : void
25+
>cbThing : (x: (x: string) => void) => void
26+
>type => { /** @type {LogEntry} */ const logEntry = { time: Date.now(), type, };} : (type: string) => void
27+
>type : string
28+
29+
/** @type {LogEntry} */
30+
const logEntry = {
31+
>logEntry : LogEntry
32+
>{ time: Date.now(), type, } : { time: number; type: string; }
33+
34+
time: Date.now(),
35+
>time : number
36+
>Date.now() : number
37+
>Date.now : () => number
38+
>Date : DateConstructor
39+
>now : () => number
40+
41+
type,
42+
>type : string
43+
44+
};
45+
});
46+
47+
=== tests/cases/compiler/index.js ===
48+
/** @enum {string} */
49+
const Thing = Object.freeze({
50+
>Thing : Readonly<{ a: string; b: string; }>
51+
>Object.freeze({ a: "thing", b: "chill"}) : Readonly<{ a: string; b: string; }>
52+
>Object.freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
53+
>Object : ObjectConstructor
54+
>freeze : { <T>(a: T[]): readonly T[]; <T extends Function>(f: T): T; <T>(o: T): Readonly<T>; }
55+
>{ a: "thing", b: "chill"} : { a: string; b: string; }
56+
57+
a: "thing",
58+
>a : string
59+
>"thing" : "thing"
60+
61+
b: "chill"
62+
>b : string
63+
>"chill" : "chill"
64+
65+
});
66+
67+
exports.Thing = Thing;
68+
>exports.Thing = Thing : Readonly<{ a: string; b: string; }>
69+
>exports.Thing : error
70+
>exports : typeof import("tests/cases/compiler/index")
71+
>Thing : any
72+
>Thing : Readonly<{ a: string; b: string; }>
73+
74+
/**
75+
* @param {Thing} x
76+
*/
77+
function useThing(x) {}
78+
>useThing : (x: string) => void
79+
>x : string
80+
81+
exports.useThing = useThing;
82+
>exports.useThing = useThing : (x: string) => void
83+
>exports.useThing : (x: string) => void
84+
>exports : typeof import("tests/cases/compiler/index")
85+
>useThing : (x: string) => void
86+
>useThing : (x: string) => void
87+
88+
/**
89+
* @param {(x: Thing) => void} x
90+
*/
91+
function cbThing(x) {}
92+
>cbThing : (x: (x: string) => void) => void
93+
>x : (x: string) => void
94+
95+
exports.cbThing = cbThing;
96+
>exports.cbThing = cbThing : (x: (x: string) => void) => void
97+
>exports.cbThing : (x: (x: string) => void) => void
98+
>exports : typeof import("tests/cases/compiler/index")
99+
>cbThing : (x: (x: string) => void) => void
100+
>cbThing : (x: (x: string) => void) => void
101+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// @noEmit: true
2+
// @checkJs: true
3+
// @allowJs: true
4+
// @filename: index.js
5+
/** @enum {string} */
6+
const Thing = Object.freeze({
7+
a: "thing",
8+
b: "chill"
9+
});
10+
11+
exports.Thing = Thing;
12+
13+
/**
14+
* @param {Thing} x
15+
*/
16+
function useThing(x) {}
17+
18+
exports.useThing = useThing;
19+
20+
/**
21+
* @param {(x: Thing) => void} x
22+
*/
23+
function cbThing(x) {}
24+
25+
exports.cbThing = cbThing;
26+
27+
// @filename: usage.js
28+
29+
const { Thing, useThing, cbThing } = require("./index");
30+
31+
useThing(Thing.a);
32+
33+
/**
34+
* @typedef {Object} LogEntry
35+
* @property {string} type
36+
* @property {number} time
37+
*/
38+
39+
cbThing(type => {
40+
/** @type {LogEntry} */
41+
const logEntry = {
42+
time: Date.now(),
43+
type,
44+
};
45+
});

0 commit comments

Comments
 (0)