Skip to content

Commit 9c60d5a

Browse files
authored
Dont look for properties of Object and Function type when looking to resolve named import from module with export= (#37964)
* Add tests * Dont look at object or function type when looking for members of `export=` type to be resolved by named imports Fixes #37165 * Create separate cache when skipping function and object property augmentation * Lookup in both cache if not skipObjectFunctionPropertyAugment
1 parent b00870e commit 9c60d5a

11 files changed

+291
-12
lines changed

src/compiler/checker.ts

+15-11
Original file line numberDiff line numberDiff line change
@@ -2689,7 +2689,7 @@ namespace ts {
26892689
let symbolFromVariable: Symbol | undefined;
26902690
// First check if module was specified with "export=". If so, get the member from the resolved type
26912691
if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) {
2692-
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText);
2692+
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true);
26932693
}
26942694
else {
26952695
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText);
@@ -11147,7 +11147,7 @@ namespace ts {
1114711147
return getReducedType(getApparentType(getReducedType(type)));
1114811148
}
1114911149

11150-
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
11150+
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
1115111151
let singleProp: Symbol | undefined;
1115211152
let propSet: ESMap<SymbolId, Symbol> | undefined;
1115311153
let indexTypes: Type[] | undefined;
@@ -11159,7 +11159,7 @@ namespace ts {
1115911159
for (const current of containingType.types) {
1116011160
const type = getApparentType(current);
1116111161
if (!(type === errorType || type.flags & TypeFlags.Never)) {
11162-
const prop = getPropertyOfType(type, name);
11162+
const prop = getPropertyOfType(type, name, skipObjectFunctionPropertyAugment);
1116311163
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
1116411164
if (prop) {
1116511165
if (isUnion) {
@@ -11276,20 +11276,23 @@ namespace ts {
1127611276
// constituents, in which case the isPartial flag is set when the containing type is union type. We need
1127711277
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
1127811278
// and do not appear to be present in the union type.
11279-
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
11280-
const properties = type.propertyCache || (type.propertyCache = createSymbolTable());
11281-
let property = properties.get(name);
11279+
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
11280+
let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) ||
11281+
!skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined;
1128211282
if (!property) {
11283-
property = createUnionOrIntersectionProperty(type, name);
11283+
property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
1128411284
if (property) {
11285+
const properties = skipObjectFunctionPropertyAugment ?
11286+
type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() :
11287+
type.propertyCache ||= createSymbolTable();
1128511288
properties.set(name, property);
1128611289
}
1128711290
}
1128811291
return property;
1128911292
}
1129011293

11291-
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
11292-
const property = getUnionOrIntersectionProperty(type, name);
11294+
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
11295+
const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
1129311296
// We need to filter out partial properties in union types
1129411297
return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined;
1129511298
}
@@ -11367,14 +11370,15 @@ namespace ts {
1136711370
* @param type a type to look up property from
1136811371
* @param name a name of property to look up in a given type
1136911372
*/
11370-
function getPropertyOfType(type: Type, name: __String): Symbol | undefined {
11373+
function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
1137111374
type = getReducedApparentType(type);
1137211375
if (type.flags & TypeFlags.Object) {
1137311376
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
1137411377
const symbol = resolved.members.get(name);
1137511378
if (symbol && symbolIsValue(symbol)) {
1137611379
return symbol;
1137711380
}
11381+
if (skipObjectFunctionPropertyAugment) return undefined;
1137811382
const functionType = resolved === anyFunctionType ? globalFunctionType :
1137911383
resolved.callSignatures.length ? globalCallableFunctionType :
1138011384
resolved.constructSignatures.length ? globalNewableFunctionType :
@@ -11388,7 +11392,7 @@ namespace ts {
1138811392
return getPropertyOfObjectType(globalObjectType, name);
1138911393
}
1139011394
if (type.flags & TypeFlags.UnionOrIntersection) {
11391-
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name);
11395+
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name, skipObjectFunctionPropertyAugment);
1139211396
}
1139311397
return undefined;
1139411398
}

src/compiler/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5193,7 +5193,9 @@ namespace ts {
51935193
/* @internal */
51945194
objectFlags: ObjectFlags;
51955195
/* @internal */
5196-
propertyCache: SymbolTable; // Cache of resolved properties
5196+
propertyCache?: SymbolTable; // Cache of resolved properties
5197+
/* @internal */
5198+
propertyCacheWithoutObjectFunctionPropertyAugment?: SymbolTable; // Cache of resolved properties that does not augment function or object type properties
51975199
/* @internal */
51985200
resolvedProperties: Symbol[];
51995201
/* @internal */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/compiler/bar.d.ts(1,10): error TS2305: Module '"./foo"' has no exported member 'Bar'.
2+
3+
4+
==== tests/cases/compiler/foo.d.ts (0 errors) ====
5+
export = Foo;
6+
export as namespace Foo;
7+
8+
declare namespace Foo {
9+
function foo();
10+
}
11+
12+
declare global {
13+
namespace Bar { }
14+
}
15+
16+
==== tests/cases/compiler/bar.d.ts (1 errors) ====
17+
import { Bar } from './foo';
18+
~~~
19+
!!! error TS2305: Module '"./foo"' has no exported member 'Bar'.
20+
export = Bar;
21+
export as namespace Bar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/foo.d.ts ===
2+
export = Foo;
3+
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
4+
5+
export as namespace Foo;
6+
>Foo : Symbol(Foo, Decl(foo.d.ts, 0, 13))
7+
8+
declare namespace Foo {
9+
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
10+
11+
function foo();
12+
>foo : Symbol(foo, Decl(foo.d.ts, 3, 23))
13+
}
14+
15+
declare global {
16+
>global : Symbol(global, Decl(foo.d.ts, 5, 1))
17+
18+
namespace Bar { }
19+
>Bar : Symbol(Bar, Decl(foo.d.ts, 7, 16))
20+
}
21+
22+
=== tests/cases/compiler/bar.d.ts ===
23+
import { Bar } from './foo';
24+
>Bar : Symbol(Bar, Decl(bar.d.ts, 0, 8))
25+
26+
export = Bar;
27+
>Bar : Symbol(Bar, Decl(bar.d.ts, 0, 8))
28+
29+
export as namespace Bar;
30+
>Bar : Symbol(Bar, Decl(bar.d.ts, 1, 13))
31+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/compiler/foo.d.ts ===
2+
export = Foo;
3+
>Foo : typeof Foo
4+
5+
export as namespace Foo;
6+
>Foo : typeof Foo
7+
8+
declare namespace Foo {
9+
>Foo : typeof Foo
10+
11+
function foo();
12+
>foo : () => any
13+
}
14+
15+
declare global {
16+
>global : any
17+
18+
namespace Bar { }
19+
}
20+
21+
=== tests/cases/compiler/bar.d.ts ===
22+
import { Bar } from './foo';
23+
>Bar : any
24+
25+
export = Bar;
26+
>Bar : any
27+
28+
export as namespace Bar;
29+
>Bar : any
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
tests/cases/compiler/bar.ts(1,10): error TS2305: Module '"./foo"' has no exported member 'Bar'.
2+
tests/cases/compiler/bar.ts(1,15): error TS2305: Module '"./foo"' has no exported member 'toString'.
3+
tests/cases/compiler/bar.ts(3,10): error TS2305: Module '"./foo2"' has no exported member 'a'.
4+
tests/cases/compiler/bar.ts(3,13): error TS2305: Module '"./foo2"' has no exported member 'b'.
5+
tests/cases/compiler/bar.ts(3,19): error TS2305: Module '"./foo2"' has no exported member 'd'.
6+
tests/cases/compiler/bar.ts(3,22): error TS2305: Module '"./foo2"' has no exported member 'toString'.
7+
8+
9+
==== tests/cases/compiler/foo.d.ts (0 errors) ====
10+
export = Foo;
11+
export as namespace Foo;
12+
13+
declare namespace Foo {
14+
function foo();
15+
}
16+
17+
==== tests/cases/compiler/foo2.ts (0 errors) ====
18+
let x: { a: string; c: string; } | { b: number; c: number; };
19+
export = x
20+
21+
==== tests/cases/compiler/bar.ts (6 errors) ====
22+
import { Bar, toString, foo } from './foo';
23+
~~~
24+
!!! error TS2305: Module '"./foo"' has no exported member 'Bar'.
25+
~~~~~~~~
26+
!!! error TS2305: Module '"./foo"' has no exported member 'toString'.
27+
foo();
28+
import { a, b, c, d, toString as foo2String } from './foo2';
29+
~
30+
!!! error TS2305: Module '"./foo2"' has no exported member 'a'.
31+
~
32+
!!! error TS2305: Module '"./foo2"' has no exported member 'b'.
33+
~
34+
!!! error TS2305: Module '"./foo2"' has no exported member 'd'.
35+
~~~~~~~~
36+
!!! error TS2305: Module '"./foo2"' has no exported member 'toString'.
37+
c;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [tests/cases/compiler/namedImportNonExistentName.ts] ////
2+
3+
//// [foo.d.ts]
4+
export = Foo;
5+
export as namespace Foo;
6+
7+
declare namespace Foo {
8+
function foo();
9+
}
10+
11+
//// [foo2.ts]
12+
let x: { a: string; c: string; } | { b: number; c: number; };
13+
export = x
14+
15+
//// [bar.ts]
16+
import { Bar, toString, foo } from './foo';
17+
foo();
18+
import { a, b, c, d, toString as foo2String } from './foo2';
19+
c;
20+
21+
//// [foo2.js]
22+
"use strict";
23+
var x;
24+
module.exports = x;
25+
//// [bar.js]
26+
"use strict";
27+
exports.__esModule = true;
28+
var foo_1 = require("./foo");
29+
foo_1.foo();
30+
var foo2_1 = require("./foo2");
31+
foo2_1.c;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
=== tests/cases/compiler/foo.d.ts ===
2+
export = Foo;
3+
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
4+
5+
export as namespace Foo;
6+
>Foo : Symbol(Foo, Decl(foo.d.ts, 0, 13))
7+
8+
declare namespace Foo {
9+
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
10+
11+
function foo();
12+
>foo : Symbol(foo, Decl(foo.d.ts, 3, 23))
13+
}
14+
15+
=== tests/cases/compiler/foo2.ts ===
16+
let x: { a: string; c: string; } | { b: number; c: number; };
17+
>x : Symbol(x, Decl(foo2.ts, 0, 3))
18+
>a : Symbol(a, Decl(foo2.ts, 0, 8))
19+
>c : Symbol(c, Decl(foo2.ts, 0, 19))
20+
>b : Symbol(b, Decl(foo2.ts, 0, 36))
21+
>c : Symbol(c, Decl(foo2.ts, 0, 47))
22+
23+
export = x
24+
>x : Symbol(x, Decl(foo2.ts, 0, 3))
25+
26+
=== tests/cases/compiler/bar.ts ===
27+
import { Bar, toString, foo } from './foo';
28+
>Bar : Symbol(Bar, Decl(bar.ts, 0, 8))
29+
>toString : Symbol(toString, Decl(bar.ts, 0, 13))
30+
>foo : Symbol(foo, Decl(bar.ts, 0, 23))
31+
32+
foo();
33+
>foo : Symbol(foo, Decl(bar.ts, 0, 23))
34+
35+
import { a, b, c, d, toString as foo2String } from './foo2';
36+
>a : Symbol(a, Decl(bar.ts, 2, 8))
37+
>b : Symbol(b, Decl(bar.ts, 2, 11))
38+
>c : Symbol(c, Decl(bar.ts, 2, 14))
39+
>d : Symbol(d, Decl(bar.ts, 2, 17))
40+
>foo2String : Symbol(foo2String, Decl(bar.ts, 2, 20))
41+
42+
c;
43+
>c : Symbol(c, Decl(bar.ts, 2, 14))
44+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/compiler/foo.d.ts ===
2+
export = Foo;
3+
>Foo : typeof Foo
4+
5+
export as namespace Foo;
6+
>Foo : typeof Foo
7+
8+
declare namespace Foo {
9+
>Foo : typeof Foo
10+
11+
function foo();
12+
>foo : () => any
13+
}
14+
15+
=== tests/cases/compiler/foo2.ts ===
16+
let x: { a: string; c: string; } | { b: number; c: number; };
17+
>x : { a: string; c: string; } | { b: number; c: number; }
18+
>a : string
19+
>c : string
20+
>b : number
21+
>c : number
22+
23+
export = x
24+
>x : { a: string; c: string; } | { b: number; c: number; }
25+
26+
=== tests/cases/compiler/bar.ts ===
27+
import { Bar, toString, foo } from './foo';
28+
>Bar : any
29+
>toString : any
30+
>foo : () => any
31+
32+
foo();
33+
>foo() : any
34+
>foo : () => any
35+
36+
import { a, b, c, d, toString as foo2String } from './foo2';
37+
>a : any
38+
>b : any
39+
>c : string | number
40+
>d : any
41+
>toString : any
42+
>foo2String : any
43+
44+
c;
45+
>c : string | number
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @filename: foo.d.ts
2+
export = Foo;
3+
export as namespace Foo;
4+
5+
declare namespace Foo {
6+
function foo();
7+
}
8+
9+
declare global {
10+
namespace Bar { }
11+
}
12+
13+
// @filename: bar.d.ts
14+
import { Bar } from './foo';
15+
export = Bar;
16+
export as namespace Bar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @filename: foo.d.ts
2+
export = Foo;
3+
export as namespace Foo;
4+
5+
declare namespace Foo {
6+
function foo();
7+
}
8+
9+
// @filename: foo2.ts
10+
let x: { a: string; c: string; } | { b: number; c: number; };
11+
export = x
12+
13+
// @filename: bar.ts
14+
import { Bar, toString, foo } from './foo';
15+
foo();
16+
import { a, b, c, d, toString as foo2String } from './foo2';
17+
c;

0 commit comments

Comments
 (0)