Skip to content

Commit 7d77ecb

Browse files
committed
JSDoc type reference understands require with entity name (#34804)
* resolve require with entity name postfix For example, `require("x").c`. This is the value equivalent of `import("x").a.b.c`, but the syntax tree is not as nicely designed for this purpose. Fixes #34802 * Add bug number to test * Add optional chain test
1 parent 787ff34 commit 7d77ecb

File tree

4 files changed

+153
-7
lines changed

4 files changed

+153
-7
lines changed

src/compiler/checker.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -10759,14 +10759,17 @@ namespace ts {
1075910759
let typeType = valueType;
1076010760
if (symbol.valueDeclaration) {
1076110761
const decl = getRootDeclaration(symbol.valueDeclaration);
10762-
const isRequireAlias = isVariableDeclaration(decl)
10763-
&& decl.initializer
10764-
&& isCallExpression(decl.initializer)
10765-
&& isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true)
10766-
&& valueType.symbol;
10767-
const isImportType = node.kind === SyntaxKind.ImportType;
10762+
let isRequireAlias = false;
10763+
if (isVariableDeclaration(decl) && decl.initializer) {
10764+
let expr = decl.initializer;
10765+
// skip past entity names, eg `require("x").a.b.c`
10766+
while (isPropertyAccessExpression(expr)) {
10767+
expr = expr.expression;
10768+
}
10769+
isRequireAlias = isCallExpression(expr) && isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !!valueType.symbol;
10770+
}
1076810771
const isDelayedMergeClass = symbol !== valueType.symbol && getMergedSymbol(symbol) === valueType.symbol;
10769-
if (isRequireAlias || isImportType || isDelayedMergeClass) {
10772+
if (isRequireAlias || node.kind === SyntaxKind.ImportType || isDelayedMergeClass) {
1077010773
typeType = getTypeReferenceType(node, valueType.symbol);
1077110774
}
1077210775
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
=== tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js ===
2+
// #34802
3+
4+
const C = require('./ex').C;
5+
>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 2, 5))
6+
>require('./ex').C : Symbol(C, Decl(ex.d.ts, 0, 0))
7+
>require : Symbol(require)
8+
>'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0))
9+
>C : Symbol(C, Decl(ex.d.ts, 0, 0))
10+
11+
const D = require('./ex')?.C;
12+
>D : Symbol(D, Decl(jsdocTypeReferenceToImport.js, 3, 5))
13+
>require('./ex')?.C : Symbol(C, Decl(ex.d.ts, 0, 0))
14+
>require : Symbol(require)
15+
>'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0))
16+
>C : Symbol(C, Decl(ex.d.ts, 0, 0))
17+
18+
/** @type {C} c */
19+
var c = new C()
20+
>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3))
21+
>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 2, 5))
22+
23+
c.start
24+
>c.start : Symbol(C.start, Decl(ex.d.ts, 0, 16))
25+
>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3))
26+
>start : Symbol(C.start, Decl(ex.d.ts, 0, 16))
27+
28+
c.end
29+
>c.end : Symbol(C.end, Decl(ex.d.ts, 1, 17))
30+
>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3))
31+
>end : Symbol(C.end, Decl(ex.d.ts, 1, 17))
32+
33+
/** @type {D} c */
34+
var d = new D()
35+
>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3))
36+
>D : Symbol(D, Decl(jsdocTypeReferenceToImport.js, 3, 5))
37+
38+
d.start
39+
>d.start : Symbol(C.start, Decl(ex.d.ts, 0, 16))
40+
>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3))
41+
>start : Symbol(C.start, Decl(ex.d.ts, 0, 16))
42+
43+
d.end
44+
>d.end : Symbol(C.end, Decl(ex.d.ts, 1, 17))
45+
>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3))
46+
>end : Symbol(C.end, Decl(ex.d.ts, 1, 17))
47+
48+
=== tests/cases/conformance/jsdoc/ex.d.ts ===
49+
export class C {
50+
>C : Symbol(C, Decl(ex.d.ts, 0, 0))
51+
52+
start: number
53+
>start : Symbol(C.start, Decl(ex.d.ts, 0, 16))
54+
55+
end: number
56+
>end : Symbol(C.end, Decl(ex.d.ts, 1, 17))
57+
}
58+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js ===
2+
// #34802
3+
4+
const C = require('./ex').C;
5+
>C : typeof import("tests/cases/conformance/jsdoc/ex").C
6+
>require('./ex').C : typeof import("tests/cases/conformance/jsdoc/ex").C
7+
>require('./ex') : typeof import("tests/cases/conformance/jsdoc/ex")
8+
>require : any
9+
>'./ex' : "./ex"
10+
>C : typeof import("tests/cases/conformance/jsdoc/ex").C
11+
12+
const D = require('./ex')?.C;
13+
>D : typeof import("tests/cases/conformance/jsdoc/ex").C
14+
>require('./ex')?.C : typeof import("tests/cases/conformance/jsdoc/ex").C
15+
>require('./ex') : typeof import("tests/cases/conformance/jsdoc/ex")
16+
>require : any
17+
>'./ex' : "./ex"
18+
>C : typeof import("tests/cases/conformance/jsdoc/ex").C
19+
20+
/** @type {C} c */
21+
var c = new C()
22+
>c : import("tests/cases/conformance/jsdoc/ex").C
23+
>new C() : import("tests/cases/conformance/jsdoc/ex").C
24+
>C : typeof import("tests/cases/conformance/jsdoc/ex").C
25+
26+
c.start
27+
>c.start : number
28+
>c : import("tests/cases/conformance/jsdoc/ex").C
29+
>start : number
30+
31+
c.end
32+
>c.end : number
33+
>c : import("tests/cases/conformance/jsdoc/ex").C
34+
>end : number
35+
36+
/** @type {D} c */
37+
var d = new D()
38+
>d : import("tests/cases/conformance/jsdoc/ex").C
39+
>new D() : import("tests/cases/conformance/jsdoc/ex").C
40+
>D : typeof import("tests/cases/conformance/jsdoc/ex").C
41+
42+
d.start
43+
>d.start : number
44+
>d : import("tests/cases/conformance/jsdoc/ex").C
45+
>start : number
46+
47+
d.end
48+
>d.end : number
49+
>d : import("tests/cases/conformance/jsdoc/ex").C
50+
>end : number
51+
52+
=== tests/cases/conformance/jsdoc/ex.d.ts ===
53+
export class C {
54+
>C : C
55+
56+
start: number
57+
>start : number
58+
59+
end: number
60+
>end : number
61+
}
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// #34802
2+
// @Filename: jsdocTypeReferenceToImport.js
3+
// @noEmit: true
4+
// @allowJs: true
5+
// @checkJs: true
6+
7+
const C = require('./ex').C;
8+
const D = require('./ex')?.C;
9+
/** @type {C} c */
10+
var c = new C()
11+
c.start
12+
c.end
13+
14+
/** @type {D} c */
15+
var d = new D()
16+
d.start
17+
d.end
18+
19+
// @Filename: ex.d.ts
20+
export class C {
21+
start: number
22+
end: number
23+
}

0 commit comments

Comments
 (0)