Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4937d9c

Browse files
author
Andy Hanson
committed
Allow untyped imports
1 parentb5ba315 commit4937d9c

File tree

24 files changed

+402
-25
lines changed

24 files changed

+402
-25
lines changed

‎src/compiler/checker.ts‎

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ namespace ts {
10691069
const moduleSymbol = resolveExternalModuleName(node, (<ImportDeclaration>node.parent).moduleSpecifier);
10701070

10711071
if (moduleSymbol) {
1072-
const exportDefaultSymbol =isShorthandAmbientModuleSymbol(moduleSymbol) ?
1072+
const exportDefaultSymbol =isUntypedModuleSymbol(moduleSymbol) ?
10731073
moduleSymbol :
10741074
moduleSymbol.exports["export="] ?
10751075
getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") :
@@ -1145,7 +1145,7 @@ namespace ts {
11451145
if (targetSymbol) {
11461146
const name = specifier.propertyName || specifier.name;
11471147
if (name.text) {
1148-
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
1148+
if (isUntypedModuleSymbol(moduleSymbol)) {
11491149
return moduleSymbol;
11501150
}
11511151

@@ -1365,8 +1365,9 @@ namespace ts {
13651365
}
13661366

13671367
const isRelative = isExternalModuleNameRelative(moduleName);
1368+
const quotedName = '"' + moduleName + '"';
13681369
if (!isRelative) {
1369-
const symbol = getSymbol(globals,'"' + moduleName + '"', SymbolFlags.ValueModule);
1370+
const symbol = getSymbol(globals,quotedName, SymbolFlags.ValueModule);
13701371
if (symbol) {
13711372
// merged symbol is module declaration symbol combined with all augmentations
13721373
return getMergedSymbol(symbol);
@@ -1395,6 +1396,28 @@ namespace ts {
13951396
}
13961397
}
13971398

1399+
// May be an untyped module. If so, ignore resolutionDiagnostic.
1400+
if (!isRelative && resolvedModule && !extensionIsTypeScript(resolvedModule.extension)) {
1401+
if (compilerOptions.noImplicitAny) {
1402+
if (moduleNotFoundError) {
1403+
error(errorNode,
1404+
Diagnostics.A_package_for_0_was_found_at_1_but_is_untyped_Because_noImplicitAny_is_enabled_this_package_must_have_a_declaration,
1405+
moduleReference,
1406+
resolvedModule.resolvedFileName);
1407+
}
1408+
return undefined;
1409+
}
1410+
1411+
// Create a new symbol to represent the untyped module and store it in globals.
1412+
// This provides a name to the module. See the test tests/cases/fourslash/untypedModuleImport.ts
1413+
const newSymbol = createSymbol(SymbolFlags.ValueModule, quotedName);
1414+
// Module symbols are expected to have 'exports', although since this is an untyped module it can be empty.
1415+
newSymbol.exports = createMap<Symbol>();
1416+
// Cache it so subsequent accesses will return the same module.
1417+
globals[quotedName] = newSymbol;
1418+
return newSymbol;
1419+
}
1420+
13981421
if (moduleNotFoundError) {
13991422
// report errors only if it was requested
14001423
if (resolutionDiagnostic) {
@@ -3462,7 +3485,7 @@ namespace ts {
34623485
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
34633486
const links = getSymbolLinks(symbol);
34643487
if (!links.type) {
3465-
if (symbol.valueDeclaration.kind === SyntaxKind.ModuleDeclaration &&isShorthandAmbientModuleSymbol(symbol)) {
3488+
if (symbol.flags & SymbolFlags.Module &&isUntypedModuleSymbol(symbol)) {
34663489
links.type = anyType;
34673490
}
34683491
else {
@@ -19011,7 +19034,7 @@ namespace ts {
1901119034

1901219035
function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean {
1901319036
let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression);
19014-
if (!moduleSymbol ||isShorthandAmbientModuleSymbol(moduleSymbol)) {
19037+
if (!moduleSymbol ||isUntypedModuleSymbol(moduleSymbol)) {
1901519038
// If the module is not found or is shorthand, assume that it may export a value.
1901619039
return true;
1901719040
}
@@ -19512,7 +19535,7 @@ namespace ts {
1951219535
(typeReferenceDirectives || (typeReferenceDirectives = [])).push(typeReferenceDirective);
1951319536
}
1951419537
else {
19515-
// found at least one entry that does not originate from type reference directive
19538+
// found at least one entry that does not originate from type reference directive
1951619539
return undefined;
1951719540
}
1951819541
}

‎src/compiler/diagnosticMessages.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2869,6 +2869,10 @@
28692869
"category":"Error",
28702870
"code":6143
28712871
},
2872+
"A package for '{0}' was found at '{1}', but is untyped. Because '--noImplicitAny' is enabled, this package must have a declaration.": {
2873+
"category":"Error",
2874+
"code":6144
2875+
},
28722876
"Variable '{0}' implicitly has an '{1}' type.": {
28732877
"category":"Error",
28742878
"code":7005

‎src/compiler/program.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,7 @@ namespace ts {
13241324
// - it's not a top level JavaScript module that exceeded the search max
13251325
constelideImport=isJsFileFromNodeModules&&currentNodeModulesDepth>maxNodeModuleJsDepth;
13261326
// Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs')
1327+
// This may still end up being an untyped module -- the file won't be included but imports will be allowed.
13271328
constshouldAddFile=resolvedFileName&&!getResolutionDiagnostic(options,resolution)&&!options.noResolve&&i<file.imports.length&&!elideImport;
13281329

13291330
if(elideImport){
@@ -1571,8 +1572,9 @@ namespace ts {
15711572

15721573
/*@internal */
15731574
/**
1574-
* Returns a DiagnosticMessage if wecan'tuse a resolved module due to its extension.
1575+
* Returns a DiagnosticMessage if wewon'tinclude a resolved module due to its extension.
15751576
* The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
1577+
* This returns a diagnostic even if the module will be an untyped module.
15761578
*/
15771579
exportfunctiongetResolutionDiagnostic(options:CompilerOptions,{ extension}:ResolvedModule):DiagnosticMessage|undefined{
15781580
switch(extension){

‎src/compiler/utilities.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,9 @@ namespace ts {
406406
((<ModuleDeclaration>node).name.kind===SyntaxKind.StringLiteral||isGlobalScopeAugmentation(<ModuleDeclaration>node));
407407
}
408408

409-
exportfunctionisShorthandAmbientModuleSymbol(moduleSymbol:Symbol):boolean{
410-
returnisShorthandAmbientModule(moduleSymbol.valueDeclaration);
409+
/** Given a symbol for a module, checks that it is either an untyped import or a shorthand ambient module. */
410+
exportfunctionisUntypedModuleSymbol(moduleSymbol:Symbol):boolean{
411+
return!moduleSymbol.valueDeclaration||isShorthandAmbientModule(moduleSymbol.valueDeclaration);
411412
}
412413

413414
functionisShorthandAmbientModule(node:Node):boolean{

‎src/harness/harness.ts‎

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,22 +1108,7 @@ namespace Harness {
11081108
constoption=getCommandLineOption(name);
11091109
if(option){
11101110
consterrors:ts.Diagnostic[]=[];
1111-
switch(option.type){
1112-
case"boolean":
1113-
options[option.name]=value.toLowerCase()==="true";
1114-
break;
1115-
case"string":
1116-
options[option.name]=value;
1117-
break;
1118-
// If not a primitive, the possible types are specified in what is effectively a map of options.
1119-
case"list":
1120-
options[option.name]=ts.parseListTypeOption(<ts.CommandLineOptionOfListType>option,value,errors);
1121-
break;
1122-
default:
1123-
options[option.name]=ts.parseCustomTypeOption(<ts.CommandLineOptionOfCustomType>option,value,errors);
1124-
break;
1125-
}
1126-
1111+
options[option.name]=optionValue(option,value,errors);
11271112
if(errors.length>0){
11281113
thrownewError(`Unknown value '${value}' for compiler option '${name}'.`);
11291114
}
@@ -1135,6 +1120,27 @@ namespace Harness {
11351120
}
11361121
}
11371122

1123+
functionoptionValue(option:ts.CommandLineOption,value:string,errors:ts.Diagnostic[]):any{
1124+
switch(option.type){
1125+
case"boolean":
1126+
returnvalue.toLowerCase()==="true";
1127+
case"string":
1128+
returnvalue;
1129+
case"number":{
1130+
constnumber=parseInt(value,10);
1131+
if(isNaN(number)){
1132+
thrownewError(`Value must be a number, got:${JSON.stringify(value)}`);
1133+
}
1134+
returnnumber;
1135+
}
1136+
// If not a primitive, the possible types are specified in what is effectively a map of options.
1137+
case"list":
1138+
returnts.parseListTypeOption(<ts.CommandLineOptionOfListType>option,value,errors);
1139+
default:
1140+
returnts.parseCustomTypeOption(<ts.CommandLineOptionOfCustomType>option,value,errors);
1141+
}
1142+
}
1143+
11381144
exportinterfaceTestFile{
11391145
unitName:string;
11401146
content:string;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/moduleResolution/untypedModuleImport.ts] ////
2+
3+
//// [index.js]
4+
// This tests that importing from a JS file globally works in an untyped way.
5+
// (Assuming we don't have `--noImplicitAny` or `--allowJs`.)
6+
7+
Thisfileisnotprocessed.
8+
9+
//// [a.ts]
10+
import*asfoofrom"foo";
11+
foo.bar();
12+
13+
//// [b.ts]
14+
importfoo=require("foo");
15+
foo();
16+
17+
//// [c.ts]
18+
importfoo,{bar}from"foo";
19+
import"./a";
20+
import"./b";
21+
foo(bar());
22+
23+
24+
//// [a.js]
25+
"use strict";
26+
varfoo=require("foo");
27+
foo.bar();
28+
//// [b.js]
29+
"use strict";
30+
varfoo=require("foo");
31+
foo();
32+
//// [c.js]
33+
"use strict";
34+
varfoo_1=require("foo");
35+
require("./a");
36+
require("./b");
37+
foo_1["default"](foo_1.bar());
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== /c.ts ===
2+
import foo, { bar } from "foo";
3+
>foo : Symbol(foo, Decl(c.ts, 0, 6))
4+
>bar : Symbol(bar, Decl(c.ts, 0, 13))
5+
6+
import "./a";
7+
import "./b";
8+
foo(bar());
9+
>foo : Symbol(foo, Decl(c.ts, 0, 6))
10+
>bar : Symbol(bar, Decl(c.ts, 0, 13))
11+
12+
=== /a.ts ===
13+
import * as foo from "foo";
14+
>foo : Symbol(foo, Decl(a.ts, 0, 6))
15+
16+
foo.bar();
17+
>foo : Symbol(foo, Decl(a.ts, 0, 6))
18+
19+
=== /b.ts ===
20+
import foo = require("foo");
21+
>foo : Symbol(foo, Decl(b.ts, 0, 0))
22+
23+
foo();
24+
>foo : Symbol(foo, Decl(b.ts, 0, 0))
25+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== /c.ts ===
2+
import foo, { bar } from "foo";
3+
>foo : any
4+
>bar : any
5+
6+
import "./a";
7+
import "./b";
8+
foo(bar());
9+
>foo(bar()) : any
10+
>foo : any
11+
>bar() : any
12+
>bar : any
13+
14+
=== /a.ts ===
15+
import * as foo from "foo";
16+
>foo : any
17+
18+
foo.bar();
19+
>foo.bar() : any
20+
>foo.bar : any
21+
>foo : any
22+
>bar : any
23+
24+
=== /b.ts ===
25+
import foo = require("foo");
26+
>foo : any
27+
28+
foo();
29+
>foo() : any
30+
>foo : any
31+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [tests/cases/conformance/moduleResolution/untypedModuleImport_allowJs.ts] ////
2+
3+
//// [index.js]
4+
// Same as untypedModuleImport.ts but with --allowJs, so the package will actually be typed.
5+
6+
exports.default={bar(){return0;}}
7+
8+
//// [a.ts]
9+
importfoofrom"foo";
10+
foo.bar();
11+
12+
13+
//// [a.js]
14+
"use strict";
15+
varfoo_1=require("foo");
16+
foo_1["default"].bar();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== /a.ts ===
2+
import foo from "foo";
3+
>foo : Symbol(foo, Decl(a.ts, 0, 6))
4+
5+
foo.bar();
6+
>foo.bar : Symbol(bar, Decl(index.js, 2, 19))
7+
>foo : Symbol(foo, Decl(a.ts, 0, 6))
8+
>bar : Symbol(bar, Decl(index.js, 2, 19))
9+
10+
=== /node_modules/foo/index.js ===
11+
// Same as untypedModuleImport.ts but with --allowJs, so the package will actually be typed.
12+
13+
exports.default = { bar() { return 0; } }
14+
>exports : Symbol(default, Decl(index.js, 0, 0))
15+
>default : Symbol(default, Decl(index.js, 0, 0))
16+
>bar : Symbol(bar, Decl(index.js, 2, 19))
17+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp