Fix name resolution of exports in JS (#27394)

The ad-hoc name resolution rule for `exports` forgets to check the
requested meaning. When `getTypeReferenceType` calls`
resolveTypeReferenceName` with `Type` only in order to give an error
when the program uses a value like a type, it is incorrectly able to
resolve `exports` instead of producing an error. Then this incorrect
symbol gets treated like an alias, which it isn't, causing the assert.

The fix, for now, is to make resolution of `exports` check the requested
meaning so that it only resolves when `Value` is requested. This makes
the above code an error ("Cannot use the namespace 'exports' as a
type."), but I think this is fine for a bug fix. We can decide later if
`exports` should behave like other expandos and be a legal type
reference.

Note that the name actually does resolve correctly, so JS users will get
the desired completions. They'll just have an error to suppress if they
have checkJs on.
This commit is contained in:
Nathan Shively-Sanders 2018-10-08 08:53:21 -07:00 committed by GitHub
parent 36e212bca3
commit 95dc1f2574
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 1 deletions

View File

@ -1456,7 +1456,7 @@ namespace ts {
if (!result) {
if (lastLocation) {
Debug.assert(lastLocation.kind === SyntaxKind.SourceFile);
if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports") {
if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) {
return lastLocation.symbol;
}
}

View File

@ -0,0 +1,13 @@
tests/cases/conformance/jsdoc/bug27342.js(3,11): error TS2709: Cannot use namespace 'exports' as a type.
==== tests/cases/conformance/jsdoc/bug27342.js (1 errors) ====
module.exports = {}
/**
* @type {exports}
~~~~~~~
!!! error TS2709: Cannot use namespace 'exports' as a type.
*/
var x

View File

@ -0,0 +1,13 @@
=== tests/cases/conformance/jsdoc/bug27342.js ===
module.exports = {}
>module.exports : Symbol("tests/cases/conformance/jsdoc/bug27342", Decl(bug27342.js, 0, 0))
>module : Symbol(module, Decl(bug27342.js, 0, 0))
>exports : Symbol("tests/cases/conformance/jsdoc/bug27342", Decl(bug27342.js, 0, 0))
/**
* @type {exports}
*/
var x
>x : Symbol(x, Decl(bug27342.js, 4, 3))

View File

@ -0,0 +1,15 @@
=== tests/cases/conformance/jsdoc/bug27342.js ===
module.exports = {}
>module.exports = {} : typeof import("tests/cases/conformance/jsdoc/bug27342")
>module.exports : typeof import("tests/cases/conformance/jsdoc/bug27342")
>module : { "tests/cases/conformance/jsdoc/bug27342": typeof import("tests/cases/conformance/jsdoc/bug27342"); }
>exports : typeof import("tests/cases/conformance/jsdoc/bug27342")
>{} : {}
/**
* @type {exports}
*/
var x
>x : typeof import("tests/cases/conformance/jsdoc/bug27342")

View File

@ -0,0 +1,10 @@
// @allowJs: true
// @noEmit: true
// @checkJs: true
// @Filename: bug27342.js
module.exports = {}
/**
* @type {exports}
*/
var x