Skip to content

Commit 428bb26

Browse files
author
Andy Hanson
committed
Use a symbol for untyped modules to distinguish from unknownSymbol
1 parent 9fec775 commit 428bb26

File tree

6 files changed

+64
-9
lines changed

6 files changed

+64
-9
lines changed

src/compiler/checker.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ namespace ts {
10991099
const moduleSymbol = resolveExternalModuleName(node, (<ImportDeclaration>node.parent).moduleSpecifier);
11001100

11011101
if (moduleSymbol) {
1102-
const exportDefaultSymbol = isShorthandAmbientModuleSymbol(moduleSymbol) ?
1102+
const exportDefaultSymbol = isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol) ?
11031103
moduleSymbol :
11041104
moduleSymbol.exports["export="] ?
11051105
getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") :
@@ -1175,7 +1175,7 @@ namespace ts {
11751175
if (targetSymbol) {
11761176
const name = specifier.propertyName || specifier.name;
11771177
if (name.text) {
1178-
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
1178+
if (isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) {
11791179
return moduleSymbol;
11801180
}
11811181

@@ -1427,15 +1427,19 @@ namespace ts {
14271427
Debug.assert(!!moduleNotFoundError);
14281428
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
14291429
error(errorNode, diag, moduleName, resolvedModule.resolvedFileName);
1430+
return undefined;
14301431
}
14311432
else if (compilerOptions.noImplicitAny && moduleNotFoundError) {
14321433
error(errorNode,
14331434
Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type,
14341435
moduleReference,
14351436
resolvedModule.resolvedFileName);
1437+
return undefined;
14361438
}
1437-
// Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first.
1438-
return undefined;
1439+
// Unlike a failed import, an untyped module produces a dummy symbol. This is checked for by `isUntypedOrShorthandAmbientModuleSymbol`.
1440+
const untypedSymbol = createSymbol(SymbolFlags.ValueModule, `"${moduleName}"`);
1441+
untypedSymbol.exports = createMap<Symbol>();
1442+
return untypedSymbol;
14391443
}
14401444

14411445
if (moduleNotFoundError) {
@@ -3575,7 +3579,7 @@ namespace ts {
35753579
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
35763580
const links = getSymbolLinks(symbol);
35773581
if (!links.type) {
3578-
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
3582+
if (symbol.flags & SymbolFlags.Module && isUntypedOrShorthandAmbientModuleSymbol(symbol)) {
35793583
links.type = anyType;
35803584
}
35813585
else {
@@ -19610,7 +19614,7 @@ namespace ts {
1961019614

1961119615
function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean {
1961219616
let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression);
19613-
if (!moduleSymbol || isShorthandAmbientModuleSymbol(moduleSymbol)) {
19617+
if (!moduleSymbol || isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) {
1961419618
// If the module is not found or is shorthand, assume that it may export a value.
1961519619
return true;
1961619620
}

src/compiler/utilities.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,9 @@ namespace ts {
388388
}
389389

390390
/** Given a symbol for a module, checks that it is either an untyped import or a shorthand ambient module. */
391-
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
392-
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
391+
//rename
392+
export function isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
393+
return !moduleSymbol.valueDeclaration || isShorthandAmbientModule(moduleSymbol.valueDeclaration);
393394
}
394395

395396
function isShorthandAmbientModule(node: Node): boolean {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/a.ts(2,17): error TS2507: Type 'any' is not a constructor function type.
2+
3+
4+
==== /a.ts (1 errors) ====
5+
import Foo from "foo";
6+
class A extends Foo { }
7+
~~~
8+
!!! error TS2507: Type 'any' is not a constructor function type.
9+
10+
==== /node_modules/foo/index.js (0 errors) ====
11+
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
12+
13+
This file is not read.
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [tests/cases/compiler/extendsUntypedModule.ts] ////
2+
3+
//// [index.js]
4+
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
5+
6+
This file is not read.
7+
8+
//// [a.ts]
9+
import Foo from "foo";
10+
class A extends Foo { }
11+
12+
13+
//// [a.js]
14+
"use strict";
15+
var __extends = (this && this.__extends) || function (d, b) {
16+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
17+
function __() { this.constructor = d; }
18+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
19+
};
20+
var foo_1 = require("foo");
21+
var A = (function (_super) {
22+
__extends(A, _super);
23+
function A() {
24+
return _super.apply(this, arguments) || this;
25+
}
26+
return A;
27+
}(foo_1["default"]));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Test that extending an untyped module is an error, unlike extending unknownSymbol.
2+
// @noImplicitReferences: true
3+
4+
// @Filename: /node_modules/foo/index.js
5+
This file is not read.
6+
7+
// @Filename: /a.ts
8+
import Foo from "foo";
9+
class A extends Foo { }

tests/cases/fourslash/untypedModuleImport.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ verify.numberOfErrorsInCurrentFile(0);
1313

1414
goTo.marker("fooModule");
1515
verify.goToDefinitionIs([]);
16-
verify.quickInfoIs("");
16+
verify.quickInfoIs('module "foo"');
1717
verify.referencesAre([])
1818

1919
goTo.marker("foo");

0 commit comments

Comments
 (0)