mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
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
This commit is contained in:
+15
-11
@@ -2689,7 +2689,7 @@ namespace ts {
|
||||
let symbolFromVariable: Symbol | undefined;
|
||||
// First check if module was specified with "export=". If so, get the member from the resolved type
|
||||
if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) {
|
||||
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText);
|
||||
symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true);
|
||||
}
|
||||
else {
|
||||
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText);
|
||||
@@ -11147,7 +11147,7 @@ namespace ts {
|
||||
return getReducedType(getApparentType(getReducedType(type)));
|
||||
}
|
||||
|
||||
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
|
||||
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
|
||||
let singleProp: Symbol | undefined;
|
||||
let propSet: ESMap<SymbolId, Symbol> | undefined;
|
||||
let indexTypes: Type[] | undefined;
|
||||
@@ -11159,7 +11159,7 @@ namespace ts {
|
||||
for (const current of containingType.types) {
|
||||
const type = getApparentType(current);
|
||||
if (!(type === errorType || type.flags & TypeFlags.Never)) {
|
||||
const prop = getPropertyOfType(type, name);
|
||||
const prop = getPropertyOfType(type, name, skipObjectFunctionPropertyAugment);
|
||||
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
|
||||
if (prop) {
|
||||
if (isUnion) {
|
||||
@@ -11276,20 +11276,23 @@ namespace ts {
|
||||
// constituents, in which case the isPartial flag is set when the containing type is union type. We need
|
||||
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
|
||||
// and do not appear to be present in the union type.
|
||||
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
|
||||
const properties = type.propertyCache || (type.propertyCache = createSymbolTable());
|
||||
let property = properties.get(name);
|
||||
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
|
||||
let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) ||
|
||||
!skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined;
|
||||
if (!property) {
|
||||
property = createUnionOrIntersectionProperty(type, name);
|
||||
property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
|
||||
if (property) {
|
||||
const properties = skipObjectFunctionPropertyAugment ?
|
||||
type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() :
|
||||
type.propertyCache ||= createSymbolTable();
|
||||
properties.set(name, property);
|
||||
}
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
|
||||
const property = getUnionOrIntersectionProperty(type, name);
|
||||
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
|
||||
const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment);
|
||||
// We need to filter out partial properties in union types
|
||||
return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined;
|
||||
}
|
||||
@@ -11367,7 +11370,7 @@ namespace ts {
|
||||
* @param type a type to look up property from
|
||||
* @param name a name of property to look up in a given type
|
||||
*/
|
||||
function getPropertyOfType(type: Type, name: __String): Symbol | undefined {
|
||||
function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined {
|
||||
type = getReducedApparentType(type);
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
|
||||
@@ -11375,6 +11378,7 @@ namespace ts {
|
||||
if (symbol && symbolIsValue(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
if (skipObjectFunctionPropertyAugment) return undefined;
|
||||
const functionType = resolved === anyFunctionType ? globalFunctionType :
|
||||
resolved.callSignatures.length ? globalCallableFunctionType :
|
||||
resolved.constructSignatures.length ? globalNewableFunctionType :
|
||||
@@ -11388,7 +11392,7 @@ namespace ts {
|
||||
return getPropertyOfObjectType(globalObjectType, name);
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name);
|
||||
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name, skipObjectFunctionPropertyAugment);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -5193,7 +5193,9 @@ namespace ts {
|
||||
/* @internal */
|
||||
objectFlags: ObjectFlags;
|
||||
/* @internal */
|
||||
propertyCache: SymbolTable; // Cache of resolved properties
|
||||
propertyCache?: SymbolTable; // Cache of resolved properties
|
||||
/* @internal */
|
||||
propertyCacheWithoutObjectFunctionPropertyAugment?: SymbolTable; // Cache of resolved properties that does not augment function or object type properties
|
||||
/* @internal */
|
||||
resolvedProperties: Symbol[];
|
||||
/* @internal */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
tests/cases/compiler/bar.d.ts(1,10): error TS2305: Module '"./foo"' has no exported member 'Bar'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/foo.d.ts (0 errors) ====
|
||||
export = Foo;
|
||||
export as namespace Foo;
|
||||
|
||||
declare namespace Foo {
|
||||
function foo();
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace Bar { }
|
||||
}
|
||||
|
||||
==== tests/cases/compiler/bar.d.ts (1 errors) ====
|
||||
import { Bar } from './foo';
|
||||
~~~
|
||||
!!! error TS2305: Module '"./foo"' has no exported member 'Bar'.
|
||||
export = Bar;
|
||||
export as namespace Bar;
|
||||
@@ -0,0 +1,31 @@
|
||||
=== tests/cases/compiler/foo.d.ts ===
|
||||
export = Foo;
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
|
||||
|
||||
export as namespace Foo;
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 0, 13))
|
||||
|
||||
declare namespace Foo {
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
|
||||
|
||||
function foo();
|
||||
>foo : Symbol(foo, Decl(foo.d.ts, 3, 23))
|
||||
}
|
||||
|
||||
declare global {
|
||||
>global : Symbol(global, Decl(foo.d.ts, 5, 1))
|
||||
|
||||
namespace Bar { }
|
||||
>Bar : Symbol(Bar, Decl(foo.d.ts, 7, 16))
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/bar.d.ts ===
|
||||
import { Bar } from './foo';
|
||||
>Bar : Symbol(Bar, Decl(bar.d.ts, 0, 8))
|
||||
|
||||
export = Bar;
|
||||
>Bar : Symbol(Bar, Decl(bar.d.ts, 0, 8))
|
||||
|
||||
export as namespace Bar;
|
||||
>Bar : Symbol(Bar, Decl(bar.d.ts, 1, 13))
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
=== tests/cases/compiler/foo.d.ts ===
|
||||
export = Foo;
|
||||
>Foo : typeof Foo
|
||||
|
||||
export as namespace Foo;
|
||||
>Foo : typeof Foo
|
||||
|
||||
declare namespace Foo {
|
||||
>Foo : typeof Foo
|
||||
|
||||
function foo();
|
||||
>foo : () => any
|
||||
}
|
||||
|
||||
declare global {
|
||||
>global : any
|
||||
|
||||
namespace Bar { }
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/bar.d.ts ===
|
||||
import { Bar } from './foo';
|
||||
>Bar : any
|
||||
|
||||
export = Bar;
|
||||
>Bar : any
|
||||
|
||||
export as namespace Bar;
|
||||
>Bar : any
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
tests/cases/compiler/bar.ts(1,10): error TS2305: Module '"./foo"' has no exported member 'Bar'.
|
||||
tests/cases/compiler/bar.ts(1,15): error TS2305: Module '"./foo"' has no exported member 'toString'.
|
||||
tests/cases/compiler/bar.ts(3,10): error TS2305: Module '"./foo2"' has no exported member 'a'.
|
||||
tests/cases/compiler/bar.ts(3,13): error TS2305: Module '"./foo2"' has no exported member 'b'.
|
||||
tests/cases/compiler/bar.ts(3,19): error TS2305: Module '"./foo2"' has no exported member 'd'.
|
||||
tests/cases/compiler/bar.ts(3,22): error TS2305: Module '"./foo2"' has no exported member 'toString'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/foo.d.ts (0 errors) ====
|
||||
export = Foo;
|
||||
export as namespace Foo;
|
||||
|
||||
declare namespace Foo {
|
||||
function foo();
|
||||
}
|
||||
|
||||
==== tests/cases/compiler/foo2.ts (0 errors) ====
|
||||
let x: { a: string; c: string; } | { b: number; c: number; };
|
||||
export = x
|
||||
|
||||
==== tests/cases/compiler/bar.ts (6 errors) ====
|
||||
import { Bar, toString, foo } from './foo';
|
||||
~~~
|
||||
!!! error TS2305: Module '"./foo"' has no exported member 'Bar'.
|
||||
~~~~~~~~
|
||||
!!! error TS2305: Module '"./foo"' has no exported member 'toString'.
|
||||
foo();
|
||||
import { a, b, c, d, toString as foo2String } from './foo2';
|
||||
~
|
||||
!!! error TS2305: Module '"./foo2"' has no exported member 'a'.
|
||||
~
|
||||
!!! error TS2305: Module '"./foo2"' has no exported member 'b'.
|
||||
~
|
||||
!!! error TS2305: Module '"./foo2"' has no exported member 'd'.
|
||||
~~~~~~~~
|
||||
!!! error TS2305: Module '"./foo2"' has no exported member 'toString'.
|
||||
c;
|
||||
@@ -0,0 +1,31 @@
|
||||
//// [tests/cases/compiler/namedImportNonExistentName.ts] ////
|
||||
|
||||
//// [foo.d.ts]
|
||||
export = Foo;
|
||||
export as namespace Foo;
|
||||
|
||||
declare namespace Foo {
|
||||
function foo();
|
||||
}
|
||||
|
||||
//// [foo2.ts]
|
||||
let x: { a: string; c: string; } | { b: number; c: number; };
|
||||
export = x
|
||||
|
||||
//// [bar.ts]
|
||||
import { Bar, toString, foo } from './foo';
|
||||
foo();
|
||||
import { a, b, c, d, toString as foo2String } from './foo2';
|
||||
c;
|
||||
|
||||
//// [foo2.js]
|
||||
"use strict";
|
||||
var x;
|
||||
module.exports = x;
|
||||
//// [bar.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var foo_1 = require("./foo");
|
||||
foo_1.foo();
|
||||
var foo2_1 = require("./foo2");
|
||||
foo2_1.c;
|
||||
@@ -0,0 +1,44 @@
|
||||
=== tests/cases/compiler/foo.d.ts ===
|
||||
export = Foo;
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
|
||||
|
||||
export as namespace Foo;
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 0, 13))
|
||||
|
||||
declare namespace Foo {
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 1, 24))
|
||||
|
||||
function foo();
|
||||
>foo : Symbol(foo, Decl(foo.d.ts, 3, 23))
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/foo2.ts ===
|
||||
let x: { a: string; c: string; } | { b: number; c: number; };
|
||||
>x : Symbol(x, Decl(foo2.ts, 0, 3))
|
||||
>a : Symbol(a, Decl(foo2.ts, 0, 8))
|
||||
>c : Symbol(c, Decl(foo2.ts, 0, 19))
|
||||
>b : Symbol(b, Decl(foo2.ts, 0, 36))
|
||||
>c : Symbol(c, Decl(foo2.ts, 0, 47))
|
||||
|
||||
export = x
|
||||
>x : Symbol(x, Decl(foo2.ts, 0, 3))
|
||||
|
||||
=== tests/cases/compiler/bar.ts ===
|
||||
import { Bar, toString, foo } from './foo';
|
||||
>Bar : Symbol(Bar, Decl(bar.ts, 0, 8))
|
||||
>toString : Symbol(toString, Decl(bar.ts, 0, 13))
|
||||
>foo : Symbol(foo, Decl(bar.ts, 0, 23))
|
||||
|
||||
foo();
|
||||
>foo : Symbol(foo, Decl(bar.ts, 0, 23))
|
||||
|
||||
import { a, b, c, d, toString as foo2String } from './foo2';
|
||||
>a : Symbol(a, Decl(bar.ts, 2, 8))
|
||||
>b : Symbol(b, Decl(bar.ts, 2, 11))
|
||||
>c : Symbol(c, Decl(bar.ts, 2, 14))
|
||||
>d : Symbol(d, Decl(bar.ts, 2, 17))
|
||||
>foo2String : Symbol(foo2String, Decl(bar.ts, 2, 20))
|
||||
|
||||
c;
|
||||
>c : Symbol(c, Decl(bar.ts, 2, 14))
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
=== tests/cases/compiler/foo.d.ts ===
|
||||
export = Foo;
|
||||
>Foo : typeof Foo
|
||||
|
||||
export as namespace Foo;
|
||||
>Foo : typeof Foo
|
||||
|
||||
declare namespace Foo {
|
||||
>Foo : typeof Foo
|
||||
|
||||
function foo();
|
||||
>foo : () => any
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/foo2.ts ===
|
||||
let x: { a: string; c: string; } | { b: number; c: number; };
|
||||
>x : { a: string; c: string; } | { b: number; c: number; }
|
||||
>a : string
|
||||
>c : string
|
||||
>b : number
|
||||
>c : number
|
||||
|
||||
export = x
|
||||
>x : { a: string; c: string; } | { b: number; c: number; }
|
||||
|
||||
=== tests/cases/compiler/bar.ts ===
|
||||
import { Bar, toString, foo } from './foo';
|
||||
>Bar : any
|
||||
>toString : any
|
||||
>foo : () => any
|
||||
|
||||
foo();
|
||||
>foo() : any
|
||||
>foo : () => any
|
||||
|
||||
import { a, b, c, d, toString as foo2String } from './foo2';
|
||||
>a : any
|
||||
>b : any
|
||||
>c : string | number
|
||||
>d : any
|
||||
>toString : any
|
||||
>foo2String : any
|
||||
|
||||
c;
|
||||
>c : string | number
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// @filename: foo.d.ts
|
||||
export = Foo;
|
||||
export as namespace Foo;
|
||||
|
||||
declare namespace Foo {
|
||||
function foo();
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace Bar { }
|
||||
}
|
||||
|
||||
// @filename: bar.d.ts
|
||||
import { Bar } from './foo';
|
||||
export = Bar;
|
||||
export as namespace Bar;
|
||||
@@ -0,0 +1,17 @@
|
||||
// @filename: foo.d.ts
|
||||
export = Foo;
|
||||
export as namespace Foo;
|
||||
|
||||
declare namespace Foo {
|
||||
function foo();
|
||||
}
|
||||
|
||||
// @filename: foo2.ts
|
||||
let x: { a: string; c: string; } | { b: number; c: number; };
|
||||
export = x
|
||||
|
||||
// @filename: bar.ts
|
||||
import { Bar, toString, foo } from './foo';
|
||||
foo();
|
||||
import { a, b, c, d, toString as foo2String } from './foo2';
|
||||
c;
|
||||
Reference in New Issue
Block a user