mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Prevent merged class/namespace from overlapping with Record<string, unknown> (#47088)
This commit is contained in:
parent
a3d23d36cc
commit
484f1414d6
@ -21036,9 +21036,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) {
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
tests/cases/compiler/mergedClassNamespaceRecordCast.ts(3,1): error TS2352: Conversion of type 'C1' to type 'Record<string, unknown>' 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<string, unknown>' 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<string, unknown>;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2352: Conversion of type 'C1' to type 'Record<string, unknown>' 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<string, unknown>;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2352: Conversion of type 'C2' to type 'Record<string, unknown>' 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<string, unknown>;
|
||||
|
||||
45
tests/baselines/reference/mergedClassNamespaceRecordCast.js
Normal file
45
tests/baselines/reference/mergedClassNamespaceRecordCast.js
Normal file
@ -0,0 +1,45 @@
|
||||
//// [mergedClassNamespaceRecordCast.ts]
|
||||
class C1 { foo() {} }
|
||||
|
||||
new C1() as Record<string, unknown>;
|
||||
|
||||
|
||||
class C2 { foo() {} }
|
||||
namespace C2 { export const unrelated = 3; }
|
||||
|
||||
new C2() as Record<string, unknown>;
|
||||
|
||||
C2.unrelated
|
||||
new C2().unrelated
|
||||
|
||||
|
||||
namespace C3 { export const unrelated = 3; }
|
||||
|
||||
C3 as Record<string, unknown>;
|
||||
|
||||
|
||||
//// [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;
|
||||
@ -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<string, unknown>;
|
||||
>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<string, unknown>;
|
||||
>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<string, unknown>;
|
||||
>C3 : Symbol(C3, Decl(mergedClassNamespaceRecordCast.ts, 11, 18))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
=== tests/cases/compiler/mergedClassNamespaceRecordCast.ts ===
|
||||
class C1 { foo() {} }
|
||||
>C1 : C1
|
||||
>foo : () => void
|
||||
|
||||
new C1() as Record<string, unknown>;
|
||||
>new C1() as Record<string, unknown> : Record<string, unknown>
|
||||
>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<string, unknown>;
|
||||
>new C2() as Record<string, unknown> : Record<string, unknown>
|
||||
>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<string, unknown>;
|
||||
>C3 as Record<string, unknown> : Record<string, unknown>
|
||||
>C3 : typeof C3
|
||||
|
||||
17
tests/cases/compiler/mergedClassNamespaceRecordCast.ts
Normal file
17
tests/cases/compiler/mergedClassNamespaceRecordCast.ts
Normal file
@ -0,0 +1,17 @@
|
||||
class C1 { foo() {} }
|
||||
|
||||
new C1() as Record<string, unknown>;
|
||||
|
||||
|
||||
class C2 { foo() {} }
|
||||
namespace C2 { export const unrelated = 3; }
|
||||
|
||||
new C2() as Record<string, unknown>;
|
||||
|
||||
C2.unrelated
|
||||
new C2().unrelated
|
||||
|
||||
|
||||
namespace C3 { export const unrelated = 3; }
|
||||
|
||||
C3 as Record<string, unknown>;
|
||||
Loading…
x
Reference in New Issue
Block a user