Avoid a crash with @typedef in a script file. (#33847)

* Avoid a crash with `@typedef` in a script file.

Scripts (as opposed to modules) do not have a symbol object. If a script
contains a `@typdef` defined on a namespace called `exports`, TypeScript
crashes because it attempts to create an exported symbol on the
(non-existent) symbol of the SourceFile.

This change avoids the crash by explicitly checking if the source file
has a symbol object, i.e. whether it is a module.

* Add usage of exports.SomeName typedef.

* Fix bug at bind site rather than in declare func
This commit is contained in:
Martin Probst 2019-10-24 23:04:42 +02:00 committed by Wesley Wigham
parent 7cfa1dfb8a
commit a03227d60e
6 changed files with 101 additions and 2 deletions

View File

@ -2003,7 +2003,12 @@ namespace ts {
switch (getAssignmentDeclarationPropertyAccessKind(declName.parent)) {
case AssignmentDeclarationKind.ExportsProperty:
case AssignmentDeclarationKind.ModuleExports:
container = file;
if (!isExternalOrCommonJsModule(file)) {
container = undefined!;
}
else {
container = file;
}
break;
case AssignmentDeclarationKind.ThisProperty:
container = declName.parent.expression;
@ -2017,7 +2022,9 @@ namespace ts {
case AssignmentDeclarationKind.None:
return Debug.fail("Shouldn't have detected typedef or enum on non-assignment declaration");
}
declareModuleMember(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
if (container) {
declareModuleMember(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
}
container = oldContainer;
}
}

View File

@ -0,0 +1,18 @@
tests/cases/conformance/jsdoc/0.js(10,20): error TS2694: Namespace 'exports' has no exported member 'SomeName'.
==== tests/cases/conformance/jsdoc/0.js (1 errors) ====
// @ts-check
var exports = {};
/**
* @typedef {string}
*/
exports.SomeName;
/** @type {exports.SomeName} */
~~~~~~~~
!!! error TS2694: Namespace 'exports' has no exported member 'SomeName'.
const myString = 'str';

View File

@ -0,0 +1,23 @@
//// [0.js]
// @ts-check
var exports = {};
/**
* @typedef {string}
*/
exports.SomeName;
/** @type {exports.SomeName} */
const myString = 'str';
//// [0.js]
// @ts-check
var exports = {};
/**
* @typedef {string}
*/
exports.SomeName;
/** @type {exports.SomeName} */
var myString = 'str';

View File

@ -0,0 +1,16 @@
=== tests/cases/conformance/jsdoc/0.js ===
// @ts-check
var exports = {};
>exports : Symbol(exports, Decl(0.js, 2, 3))
/**
* @typedef {string}
*/
exports.SomeName;
>exports : Symbol(exports, Decl(0.js, 2, 3))
/** @type {exports.SomeName} */
const myString = 'str';
>myString : Symbol(myString, Decl(0.js, 10, 5))

View File

@ -0,0 +1,20 @@
=== tests/cases/conformance/jsdoc/0.js ===
// @ts-check
var exports = {};
>exports : {}
>{} : {}
/**
* @typedef {string}
*/
exports.SomeName;
>exports.SomeName : any
>exports : {}
>SomeName : any
/** @type {exports.SomeName} */
const myString = 'str';
>myString : any
>'str' : "str"

View File

@ -0,0 +1,15 @@
// @allowJS: true
// @suppressOutputPathCheck: true
// @filename: 0.js
// @ts-check
var exports = {};
/**
* @typedef {string}
*/
exports.SomeName;
/** @type {exports.SomeName} */
const myString = 'str';