diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ada97551aacc..23f28f98be623 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21000,9 +21000,14 @@ namespace ts { * with no call or construct signatures. */ function isObjectTypeWithInferableIndex(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) : - !!(type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 && - !typeHasCallOrConstructSignatures(type)) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); + return type.flags & TypeFlags.Intersection + ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) + : !!( + type.symbol + && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 + && !(type.symbol.flags & SymbolFlags.Class) + && !typeHasCallOrConstructSignatures(type) + ) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); } function createSymbolWithType(source: Symbol, type: Type | undefined) { diff --git a/tests/baselines/reference/mergedClassNamespaceRecordCast.errors.txt b/tests/baselines/reference/mergedClassNamespaceRecordCast.errors.txt new file mode 100644 index 0000000000000..7c170f7e7cc33 --- /dev/null +++ b/tests/baselines/reference/mergedClassNamespaceRecordCast.errors.txt @@ -0,0 +1,34 @@ +tests/cases/compiler/mergedClassNamespaceRecordCast.ts(3,1): error TS2352: Conversion of type 'C1' to type 'Record' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + Index signature for type 'string' is missing in type 'C1'. +tests/cases/compiler/mergedClassNamespaceRecordCast.ts(9,1): error TS2352: Conversion of type 'C2' to type 'Record' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + Index signature for type 'string' is missing in type 'C2'. +tests/cases/compiler/mergedClassNamespaceRecordCast.ts(12,10): error TS2339: Property 'unrelated' does not exist on type 'C2'. + + +==== tests/cases/compiler/mergedClassNamespaceRecordCast.ts (3 errors) ==== + class C1 { foo() {} } + + new C1() as Record; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Conversion of type 'C1' to type 'Record' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. +!!! error TS2352: Index signature for type 'string' is missing in type 'C1'. + + + class C2 { foo() {} } + namespace C2 { export const unrelated = 3; } + + new C2() as Record; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Conversion of type 'C2' to type 'Record' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. +!!! error TS2352: Index signature for type 'string' is missing in type 'C2'. + + C2.unrelated + new C2().unrelated + ~~~~~~~~~ +!!! error TS2339: Property 'unrelated' does not exist on type 'C2'. + + + namespace C3 { export const unrelated = 3; } + + C3 as Record; + \ No newline at end of file diff --git a/tests/baselines/reference/mergedClassNamespaceRecordCast.js b/tests/baselines/reference/mergedClassNamespaceRecordCast.js new file mode 100644 index 0000000000000..848f01d70cfbb --- /dev/null +++ b/tests/baselines/reference/mergedClassNamespaceRecordCast.js @@ -0,0 +1,45 @@ +//// [mergedClassNamespaceRecordCast.ts] +class C1 { foo() {} } + +new C1() as Record; + + +class C2 { foo() {} } +namespace C2 { export const unrelated = 3; } + +new C2() as Record; + +C2.unrelated +new C2().unrelated + + +namespace C3 { export const unrelated = 3; } + +C3 as Record; + + +//// [mergedClassNamespaceRecordCast.js] +var C1 = /** @class */ (function () { + function C1() { + } + C1.prototype.foo = function () { }; + return C1; +}()); +new C1(); +var C2 = /** @class */ (function () { + function C2() { + } + C2.prototype.foo = function () { }; + return C2; +}()); +(function (C2) { + C2.unrelated = 3; +})(C2 || (C2 = {})); +new C2(); +C2.unrelated; +new C2().unrelated; +var C3; +(function (C3) { + C3.unrelated = 3; +})(C3 || (C3 = {})); +C3; diff --git a/tests/baselines/reference/mergedClassNamespaceRecordCast.symbols b/tests/baselines/reference/mergedClassNamespaceRecordCast.symbols new file mode 100644 index 0000000000000..71f6d7c79a54e --- /dev/null +++ b/tests/baselines/reference/mergedClassNamespaceRecordCast.symbols @@ -0,0 +1,39 @@ +=== tests/cases/compiler/mergedClassNamespaceRecordCast.ts === +class C1 { foo() {} } +>C1 : Symbol(C1, Decl(mergedClassNamespaceRecordCast.ts, 0, 0)) +>foo : Symbol(C1.foo, Decl(mergedClassNamespaceRecordCast.ts, 0, 10)) + +new C1() as Record; +>C1 : Symbol(C1, Decl(mergedClassNamespaceRecordCast.ts, 0, 0)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + +class C2 { foo() {} } +>C2 : Symbol(C2, Decl(mergedClassNamespaceRecordCast.ts, 2, 36), Decl(mergedClassNamespaceRecordCast.ts, 5, 21)) +>foo : Symbol(C2.foo, Decl(mergedClassNamespaceRecordCast.ts, 5, 10)) + +namespace C2 { export const unrelated = 3; } +>C2 : Symbol(C2, Decl(mergedClassNamespaceRecordCast.ts, 2, 36), Decl(mergedClassNamespaceRecordCast.ts, 5, 21)) +>unrelated : Symbol(unrelated, Decl(mergedClassNamespaceRecordCast.ts, 6, 27)) + +new C2() as Record; +>C2 : Symbol(C2, Decl(mergedClassNamespaceRecordCast.ts, 2, 36), Decl(mergedClassNamespaceRecordCast.ts, 5, 21)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + +C2.unrelated +>C2.unrelated : Symbol(C2.unrelated, Decl(mergedClassNamespaceRecordCast.ts, 6, 27)) +>C2 : Symbol(C2, Decl(mergedClassNamespaceRecordCast.ts, 2, 36), Decl(mergedClassNamespaceRecordCast.ts, 5, 21)) +>unrelated : Symbol(C2.unrelated, Decl(mergedClassNamespaceRecordCast.ts, 6, 27)) + +new C2().unrelated +>C2 : Symbol(C2, Decl(mergedClassNamespaceRecordCast.ts, 2, 36), Decl(mergedClassNamespaceRecordCast.ts, 5, 21)) + + +namespace C3 { export const unrelated = 3; } +>C3 : Symbol(C3, Decl(mergedClassNamespaceRecordCast.ts, 11, 18)) +>unrelated : Symbol(unrelated, Decl(mergedClassNamespaceRecordCast.ts, 14, 27)) + +C3 as Record; +>C3 : Symbol(C3, Decl(mergedClassNamespaceRecordCast.ts, 11, 18)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/mergedClassNamespaceRecordCast.types b/tests/baselines/reference/mergedClassNamespaceRecordCast.types new file mode 100644 index 0000000000000..8d15fe5151291 --- /dev/null +++ b/tests/baselines/reference/mergedClassNamespaceRecordCast.types @@ -0,0 +1,46 @@ +=== tests/cases/compiler/mergedClassNamespaceRecordCast.ts === +class C1 { foo() {} } +>C1 : C1 +>foo : () => void + +new C1() as Record; +>new C1() as Record : Record +>new C1() : C1 +>C1 : typeof C1 + + +class C2 { foo() {} } +>C2 : C2 +>foo : () => void + +namespace C2 { export const unrelated = 3; } +>C2 : typeof C2 +>unrelated : 3 +>3 : 3 + +new C2() as Record; +>new C2() as Record : Record +>new C2() : C2 +>C2 : typeof C2 + +C2.unrelated +>C2.unrelated : 3 +>C2 : typeof C2 +>unrelated : 3 + +new C2().unrelated +>new C2().unrelated : any +>new C2() : C2 +>C2 : typeof C2 +>unrelated : any + + +namespace C3 { export const unrelated = 3; } +>C3 : typeof C3 +>unrelated : 3 +>3 : 3 + +C3 as Record; +>C3 as Record : Record +>C3 : typeof C3 + diff --git a/tests/cases/compiler/mergedClassNamespaceRecordCast.ts b/tests/cases/compiler/mergedClassNamespaceRecordCast.ts new file mode 100644 index 0000000000000..830cbc4e4858b --- /dev/null +++ b/tests/cases/compiler/mergedClassNamespaceRecordCast.ts @@ -0,0 +1,17 @@ +class C1 { foo() {} } + +new C1() as Record; + + +class C2 { foo() {} } +namespace C2 { export const unrelated = 3; } + +new C2() as Record; + +C2.unrelated +new C2().unrelated + + +namespace C3 { export const unrelated = 3; } + +C3 as Record;