Skip to content

Commit 16b4153

Browse files
committed
Dont look at object or function type when looking for members of export= type to be resolved by named imports
Fixes #37165
1 parent c6a4b59 commit 16b4153

9 files changed

+181
-15
lines changed

src/compiler/checker.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -2522,7 +2522,7 @@ namespace ts {
25222522
let symbolFromVariable: Symbol | undefined;
25232523
// First check if module was specified with "export=". If so, get the member from the resolved type
25242524
if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) {
2525-
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText);
2525+
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true);
25262526
}
25272527
else {
25282528
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText);
@@ -10367,7 +10367,7 @@ namespace ts {
1036710367
t;
1036810368
}
1036910369

10370-
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
10370+
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
1037110371
const propSet = createMap<Symbol>();
1037210372
let indexTypes: Type[] | undefined;
1037310373
const isUnion = containingType.flags & TypeFlags.Union;
@@ -10379,7 +10379,7 @@ namespace ts {
1037910379
for (const current of containingType.types) {
1038010380
const type = getApparentType(current);
1038110381
if (!(type === errorType || type.flags & TypeFlags.Never)) {
10382-
const prop = getPropertyOfType(type, name);
10382+
const prop = getPropertyOfType(type, name, skipObjectFunctionPropertyAugment);
1038310383
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
1038410384
if (prop && !(modifiers & excludeModifiers)) {
1038510385
if (isUnion) {
@@ -10485,20 +10485,21 @@ namespace ts {
1048510485
// constituents, in which case the isPartial flag is set when the containing type is union type. We need
1048610486
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
1048710487
// and do not appear to be present in the union type.
10488-
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
10488+
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
1048910489
const properties = type.propertyCache || (type.propertyCache = createSymbolTable());
1049010490
let property = properties.get(name);
1049110491
if (!property) {
10492-
property = createUnionOrIntersectionProperty(type, name);
10493-
if (property) {
10492+
property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
10493+
// Dont set the result since it might not be correct if skipping lookup from property of Object and function type
10494+
if (property && !skipObjectFunctionPropertyAugment) {
1049410495
properties.set(name, property);
1049510496
}
1049610497
}
1049710498
return property;
1049810499
}
1049910500

10500-
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
10501-
const property = getUnionOrIntersectionProperty(type, name);
10501+
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
10502+
const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
1050210503
// We need to filter out partial properties in union types
1050310504
return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined;
1050410505
}
@@ -10576,14 +10577,15 @@ namespace ts {
1057610577
* @param type a type to look up property from
1057710578
* @param name a name of property to look up in a given type
1057810579
*/
10579-
function getPropertyOfType(type: Type, name: __String): Symbol | undefined {
10580+
function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
1058010581
type = getApparentType(getReducedType(type));
1058110582
if (type.flags & TypeFlags.Object) {
1058210583
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
1058310584
const symbol = resolved.members.get(name);
1058410585
if (symbol && symbolIsValue(symbol)) {
1058510586
return symbol;
1058610587
}
10588+
if (skipObjectFunctionPropertyAugment) return undefined;
1058710589
const functionType = resolved === anyFunctionType ? globalFunctionType :
1058810590
resolved.callSignatures.length ? globalCallableFunctionType :
1058910591
resolved.constructSignatures.length ? globalNewableFunctionType :
@@ -10597,7 +10599,7 @@ namespace ts {
1059710599
return getPropertyOfObjectType(globalObjectType, name);
1059810600
}
1059910601
if (type.flags & TypeFlags.UnionOrIntersection) {
10600-
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name);
10602+
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name, skipObjectFunctionPropertyAugment);
1060110603
}
1060210604
return undefined;
1060310605
}
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+

tests/baselines/reference/namedImportNonExistentName.errors.txt

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
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'.
27

38

49
==== tests/cases/compiler/foo.d.ts (0 errors) ====
@@ -9,8 +14,24 @@ tests/cases/compiler/bar.ts(1,10): error TS2305: Module '"./foo"' has no exporte
914
function foo();
1015
}
1116

12-
==== tests/cases/compiler/bar.ts (1 errors) ====
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) ====
1322
import { Bar, toString, foo } from './foo';
1423
~~~
1524
!!! error TS2305: Module '"./foo"' has no exported member 'Bar'.
16-
foo();
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;

tests/baselines/reference/namedImportNonExistentName.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,24 @@ declare namespace Foo {
88
function foo();
99
}
1010

11+
//// [foo2.ts]
12+
let x: { a: string; c: string; } | { b: number; c: number; };
13+
export = x
14+
1115
//// [bar.ts]
1216
import { Bar, toString, foo } from './foo';
13-
foo();
17+
foo();
18+
import { a, b, c, d, toString as foo2String } from './foo2';
19+
c;
1420

21+
//// [foo2.js]
22+
"use strict";
23+
var x;
24+
module.exports = x;
1525
//// [bar.js]
1626
"use strict";
1727
exports.__esModule = true;
1828
var foo_1 = require("./foo");
1929
foo_1.foo();
30+
var foo2_1 = require("./foo2");
31+
foo2_1.c;

tests/baselines/reference/namedImportNonExistentName.symbols

+21
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ declare namespace Foo {
1212
>foo : Symbol(foo, Decl(foo.d.ts, 3, 23))
1313
}
1414

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+
1526
=== tests/cases/compiler/bar.ts ===
1627
import { Bar, toString, foo } from './foo';
1728
>Bar : Symbol(Bar, Decl(bar.ts, 0, 8))
@@ -21,3 +32,13 @@ import { Bar, toString, foo } from './foo';
2132
foo();
2233
>foo : Symbol(foo, Decl(bar.ts, 0, 23))
2334

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+

tests/baselines/reference/namedImportNonExistentName.types

+23-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,35 @@ declare namespace Foo {
1212
>foo : () => any
1313
}
1414

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+
1526
=== tests/cases/compiler/bar.ts ===
1627
import { Bar, toString, foo } from './foo';
1728
>Bar : any
18-
>toString : () => string
29+
>toString : any
1930
>foo : () => any
2031

2132
foo();
2233
>foo() : any
2334
>foo : () => any
2435

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+

tests/cases/compiler/namedImportNonExistentName.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ declare namespace Foo {
66
function foo();
77
}
88

9+
// @filename: foo2.ts
10+
let x: { a: string; c: string; } | { b: number; c: number; };
11+
export = x
12+
913
// @filename: bar.ts
1014
import { Bar, toString, foo } from './foo';
11-
foo();
15+
foo();
16+
import { a, b, c, d, toString as foo2String } from './foo2';
17+
c;

0 commit comments

Comments
 (0)