From b713df83bc96d061bcb9a1d9a020384a09dc1ef7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 29 Oct 2019 10:43:45 -0700 Subject: [PATCH 1/3] 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 --- src/compiler/checker.ts | 14 +++++--- .../jsdocTypeReferenceToImport.symbols | 34 ++++++++++++++++++ .../jsdocTypeReferenceToImport.types | 36 +++++++++++++++++++ .../jsdoc/jsdocTypeReferenceToImport.ts | 16 +++++++++ 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/jsdocTypeReferenceToImport.symbols create mode 100644 tests/baselines/reference/jsdocTypeReferenceToImport.types create mode 100644 tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 145e335175474..3a88ddd3f073e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10765,11 +10765,15 @@ namespace ts { let typeType = valueType; if (symbol.valueDeclaration) { const decl = getRootDeclaration(symbol.valueDeclaration); - const isRequireAlias = isVariableDeclaration(decl) - && decl.initializer - && isCallExpression(decl.initializer) - && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true) - && valueType.symbol; + let isRequireAlias = false; + if (isVariableDeclaration(decl) && decl.initializer) { + let expr = decl.initializer; + // skip past entity names, eg `require("x").a.b.c` + while (isPropertyAccessExpression(expr)) { + expr = expr.expression; + } + isRequireAlias = isCallExpression(expr) && isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !!valueType.symbol; + } if (isRequireAlias || node.kind === SyntaxKind.ImportType) { typeType = getTypeReferenceType(node, valueType.symbol); } diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.symbols b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols new file mode 100644 index 0000000000000..c093822cbf1fd --- /dev/null +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols @@ -0,0 +1,34 @@ +=== tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js === +const C = require('./ex').C; +>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 0, 5)) +>require('./ex').C : Symbol(C, Decl(ex.d.ts, 0, 0)) +>require : Symbol(require) +>'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0)) +>C : Symbol(C, Decl(ex.d.ts, 0, 0)) + +/** @type {C} c */ +var c = new C() +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) +>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 0, 5)) + +c.start +>c.start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) +>start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) + +c.end +>c.end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) +>end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) + +=== tests/cases/conformance/jsdoc/ex.d.ts === +export class C { +>C : Symbol(C, Decl(ex.d.ts, 0, 0)) + + start: number +>start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) + + end: number +>end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) +} + diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.types b/tests/baselines/reference/jsdocTypeReferenceToImport.types new file mode 100644 index 0000000000000..e5d365b3d4faa --- /dev/null +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js === +const C = require('./ex').C; +>C : typeof import("tests/cases/conformance/jsdoc/ex").C +>require('./ex').C : typeof import("tests/cases/conformance/jsdoc/ex").C +>require('./ex') : typeof import("tests/cases/conformance/jsdoc/ex") +>require : any +>'./ex' : "./ex" +>C : typeof import("tests/cases/conformance/jsdoc/ex").C + +/** @type {C} c */ +var c = new C() +>c : import("tests/cases/conformance/jsdoc/ex").C +>new C() : import("tests/cases/conformance/jsdoc/ex").C +>C : typeof import("tests/cases/conformance/jsdoc/ex").C + +c.start +>c.start : number +>c : import("tests/cases/conformance/jsdoc/ex").C +>start : number + +c.end +>c.end : number +>c : import("tests/cases/conformance/jsdoc/ex").C +>end : number + +=== tests/cases/conformance/jsdoc/ex.d.ts === +export class C { +>C : C + + start: number +>start : number + + end: number +>end : number +} + diff --git a/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts new file mode 100644 index 0000000000000..c28550852d888 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts @@ -0,0 +1,16 @@ +// @Filename: jsdocTypeReferenceToImport.js +// @noEmit: true +// @allowJs: true +// @checkJs: true + +const C = require('./ex').C; +/** @type {C} c */ +var c = new C() +c.start +c.end + +// @Filename: ex.d.ts +export class C { + start: number + end: number +} From c4eff559816f02602dbff677ed6925271e725b06 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 29 Oct 2019 10:46:07 -0700 Subject: [PATCH 2/3] Add bug number to test --- .../reference/jsdocTypeReferenceToImport.symbols | 12 +++++++----- .../reference/jsdocTypeReferenceToImport.types | 2 ++ .../conformance/jsdoc/jsdocTypeReferenceToImport.ts | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.symbols b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols index c093822cbf1fd..700cd96c423db 100644 --- a/tests/baselines/reference/jsdocTypeReferenceToImport.symbols +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols @@ -1,6 +1,8 @@ === tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js === +// #34802 + const C = require('./ex').C; ->C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 0, 5)) +>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 2, 5)) >require('./ex').C : Symbol(C, Decl(ex.d.ts, 0, 0)) >require : Symbol(require) >'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0)) @@ -8,17 +10,17 @@ const C = require('./ex').C; /** @type {C} c */ var c = new C() ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) ->C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 0, 5)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) +>C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 2, 5)) c.start >c.start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) >start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) c.end >c.end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 2, 3)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) >end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) === tests/cases/conformance/jsdoc/ex.d.ts === diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.types b/tests/baselines/reference/jsdocTypeReferenceToImport.types index e5d365b3d4faa..9b17ed0f263c9 100644 --- a/tests/baselines/reference/jsdocTypeReferenceToImport.types +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.types @@ -1,4 +1,6 @@ === tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.js === +// #34802 + const C = require('./ex').C; >C : typeof import("tests/cases/conformance/jsdoc/ex").C >require('./ex').C : typeof import("tests/cases/conformance/jsdoc/ex").C diff --git a/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts index c28550852d888..f56c3aa327abf 100644 --- a/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts +++ b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts @@ -1,3 +1,4 @@ +// #34802 // @Filename: jsdocTypeReferenceToImport.js // @noEmit: true // @allowJs: true From b65bbc57d127abbbefd99de57df36114e702f779 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 29 Oct 2019 12:53:50 -0700 Subject: [PATCH 3/3] Add optional chain test --- .../jsdocTypeReferenceToImport.symbols | 28 +++++++++++++++++-- .../jsdocTypeReferenceToImport.types | 24 ++++++++++++++++ .../jsdoc/jsdocTypeReferenceToImport.ts | 6 ++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.symbols b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols index 700cd96c423db..c7d04ff5a1627 100644 --- a/tests/baselines/reference/jsdocTypeReferenceToImport.symbols +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.symbols @@ -8,19 +8,41 @@ const C = require('./ex').C; >'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0)) >C : Symbol(C, Decl(ex.d.ts, 0, 0)) +const D = require('./ex')?.C; +>D : Symbol(D, Decl(jsdocTypeReferenceToImport.js, 3, 5)) +>require('./ex')?.C : Symbol(C, Decl(ex.d.ts, 0, 0)) +>require : Symbol(require) +>'./ex' : Symbol("tests/cases/conformance/jsdoc/ex", Decl(ex.d.ts, 0, 0)) +>C : Symbol(C, Decl(ex.d.ts, 0, 0)) + /** @type {C} c */ var c = new C() ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3)) >C : Symbol(C, Decl(jsdocTypeReferenceToImport.js, 2, 5)) c.start >c.start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3)) >start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) c.end >c.end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) ->c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 4, 3)) +>c : Symbol(c, Decl(jsdocTypeReferenceToImport.js, 5, 3)) +>end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) + +/** @type {D} c */ +var d = new D() +>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3)) +>D : Symbol(D, Decl(jsdocTypeReferenceToImport.js, 3, 5)) + +d.start +>d.start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) +>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3)) +>start : Symbol(C.start, Decl(ex.d.ts, 0, 16)) + +d.end +>d.end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) +>d : Symbol(d, Decl(jsdocTypeReferenceToImport.js, 10, 3)) >end : Symbol(C.end, Decl(ex.d.ts, 1, 17)) === tests/cases/conformance/jsdoc/ex.d.ts === diff --git a/tests/baselines/reference/jsdocTypeReferenceToImport.types b/tests/baselines/reference/jsdocTypeReferenceToImport.types index 9b17ed0f263c9..4d4fe89ae02a5 100644 --- a/tests/baselines/reference/jsdocTypeReferenceToImport.types +++ b/tests/baselines/reference/jsdocTypeReferenceToImport.types @@ -9,6 +9,14 @@ const C = require('./ex').C; >'./ex' : "./ex" >C : typeof import("tests/cases/conformance/jsdoc/ex").C +const D = require('./ex')?.C; +>D : typeof import("tests/cases/conformance/jsdoc/ex").C +>require('./ex')?.C : typeof import("tests/cases/conformance/jsdoc/ex").C +>require('./ex') : typeof import("tests/cases/conformance/jsdoc/ex") +>require : any +>'./ex' : "./ex" +>C : typeof import("tests/cases/conformance/jsdoc/ex").C + /** @type {C} c */ var c = new C() >c : import("tests/cases/conformance/jsdoc/ex").C @@ -25,6 +33,22 @@ c.end >c : import("tests/cases/conformance/jsdoc/ex").C >end : number +/** @type {D} c */ +var d = new D() +>d : import("tests/cases/conformance/jsdoc/ex").C +>new D() : import("tests/cases/conformance/jsdoc/ex").C +>D : typeof import("tests/cases/conformance/jsdoc/ex").C + +d.start +>d.start : number +>d : import("tests/cases/conformance/jsdoc/ex").C +>start : number + +d.end +>d.end : number +>d : import("tests/cases/conformance/jsdoc/ex").C +>end : number + === tests/cases/conformance/jsdoc/ex.d.ts === export class C { >C : C diff --git a/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts index f56c3aa327abf..8163988fc0c9c 100644 --- a/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts +++ b/tests/cases/conformance/jsdoc/jsdocTypeReferenceToImport.ts @@ -5,11 +5,17 @@ // @checkJs: true const C = require('./ex').C; +const D = require('./ex')?.C; /** @type {C} c */ var c = new C() c.start c.end +/** @type {D} c */ +var d = new D() +d.start +d.end + // @Filename: ex.d.ts export class C { start: number