Skip to content

Commit 9862b03

Browse files
Relax requirements on index signatures to 'any' when a type also contains a string index signature to 'any' (#43065)
* Added test. * Accepted baselines. * Allow other index signatures to 'any' if there is a string index signature to 'any'. * Accepted baselines.
1 parent ca8d9e4 commit 9862b03

6 files changed

+904
-2
lines changed

src/compiler/checker.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -19029,10 +19029,18 @@ namespace ts {
1902919029
return indexTypesIdenticalTo(source, target, kind);
1903019030
}
1903119031
const targetType = getIndexTypeOfType(target, kind);
19032-
if (!targetType || targetType.flags & TypeFlags.Any && !sourceIsPrimitive && kind === IndexKind.String) {
19033-
// Index signature of type any permits assignment from everything but primitives
19032+
if (!targetType) {
1903419033
return Ternary.True;
1903519034
}
19035+
if (targetType.flags & TypeFlags.Any && !sourceIsPrimitive) {
19036+
// An index signature of type `any` permits assignment from everything but primitives,
19037+
// provided that there is also a `string` index signature of type `any`.
19038+
const stringIndexType = kind === IndexKind.String ? targetType : getIndexTypeOfType(target, IndexKind.String);
19039+
if (stringIndexType && stringIndexType.flags & TypeFlags.Any) {
19040+
return Ternary.True;
19041+
}
19042+
19043+
}
1903619044
if (isGenericMappedType(source)) {
1903719045
// A generic mapped type { [P in K]: T } is related to a type with an index signature
1903819046
// { [x: string]: U }, and optionally with an index signature { [x: number]: V },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(43,5): error TS2322: Type 'Obj' is not assignable to type 'NumberTo<any>'.
2+
Index signature is missing in type 'Obj'.
3+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(49,5): error TS2739: Type 'StringTo<any>' is missing the following properties from type 'Obj': hello, world
4+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(50,5): error TS2739: Type 'NumberTo<any>' is missing the following properties from type 'Obj': hello, world
5+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(51,5): error TS2739: Type 'StringAndNumberTo<any>' is missing the following properties from type 'Obj': hello, world
6+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(61,5): error TS2322: Type 'Obj' is not assignable to type 'NumberTo<any>'.
7+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(65,5): error TS2322: Type 'Obj' is not assignable to type 'StringTo<any> & NumberTo<any>'.
8+
Type 'Obj' is not assignable to type 'NumberTo<any>'.
9+
Index signature is missing in type 'Obj'.
10+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(67,5): error TS2322: Type 'StringTo<any>' is not assignable to type 'Obj'.
11+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(68,5): error TS2322: Type 'NumberTo<any>' is not assignable to type 'Obj'.
12+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(69,5): error TS2739: Type 'StringTo<any> & NumberTo<any>' is missing the following properties from type 'Obj': hello, world
13+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(84,5): error TS2322: Type 'Obj' is not assignable to type 'NumberToNumber'.
14+
Index signature is missing in type 'Obj'.
15+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(88,5): error TS2322: Type 'Obj' is not assignable to type 'StringToAnyNumberToNumber'.
16+
Index signature is missing in type 'Obj'.
17+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(90,5): error TS2322: Type 'StringTo<any>' is not assignable to type 'Obj'.
18+
tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts(91,5): error TS2739: Type 'NumberTo<number>' is missing the following properties from type 'Obj': hello, world
19+
20+
21+
==== tests/cases/conformance/types/members/objectTypeWithStringAndNumberIndexSignatureToAny.ts (13 errors) ====
22+
// When checking compatibility between two types,
23+
// TypeScript should not require an index signature if
24+
// the target side index signature maps to `any` *and*
25+
// the target side has *any* string index signature to `any`.
26+
//
27+
// So an index signature like in
28+
//
29+
// { [x: number]: any }
30+
//
31+
// is still required of a source type, but neither index signature in
32+
//
33+
// { [x: number]: any, [x: string]: any; }
34+
//
35+
// should be required; *however*, the number index signature in
36+
//
37+
// { [x: number]: number, [x: string]: any; }
38+
//
39+
// should always be required.
40+
41+
interface StringTo<T> {
42+
[x: string]: T;
43+
}
44+
45+
interface NumberTo<T> {
46+
[x: number]: T;
47+
}
48+
49+
interface StringAndNumberTo<T> extends StringTo<T>, NumberTo<T> {
50+
}
51+
52+
interface Obj {
53+
hello: string;
54+
world: number;
55+
}
56+
57+
function f1(sToAny: StringTo<any>, nToAny: NumberTo<any>, bothToAny: StringAndNumberTo<any>, someObj: Obj) {
58+
sToAny = nToAny;
59+
sToAny = bothToAny;
60+
sToAny = someObj;
61+
62+
nToAny = sToAny;
63+
nToAny = bothToAny;
64+
nToAny = someObj;
65+
~~~~~~
66+
!!! error TS2322: Type 'Obj' is not assignable to type 'NumberTo<any>'.
67+
!!! error TS2322: Index signature is missing in type 'Obj'.
68+
69+
bothToAny = sToAny;
70+
bothToAny = nToAny;
71+
bothToAny = someObj;
72+
73+
someObj = sToAny;
74+
~~~~~~~
75+
!!! error TS2739: Type 'StringTo<any>' is missing the following properties from type 'Obj': hello, world
76+
someObj = nToAny;
77+
~~~~~~~
78+
!!! error TS2739: Type 'NumberTo<any>' is missing the following properties from type 'Obj': hello, world
79+
someObj = bothToAny;
80+
~~~~~~~
81+
!!! error TS2739: Type 'StringAndNumberTo<any>' is missing the following properties from type 'Obj': hello, world
82+
}
83+
84+
function f2(sToAny: StringTo<any>, nToAny: NumberTo<any>, bothToAny: StringTo<any> & NumberTo<any>, someObj: Obj) {
85+
sToAny = nToAny;
86+
sToAny = bothToAny;
87+
sToAny = someObj;
88+
89+
nToAny = sToAny;
90+
nToAny = bothToAny;
91+
nToAny = someObj;
92+
~~~~~~
93+
!!! error TS2322: Type 'Obj' is not assignable to type 'NumberTo<any>'.
94+
95+
bothToAny = sToAny;
96+
bothToAny = nToAny;
97+
bothToAny = someObj;
98+
~~~~~~~~~
99+
!!! error TS2322: Type 'Obj' is not assignable to type 'StringTo<any> & NumberTo<any>'.
100+
!!! error TS2322: Type 'Obj' is not assignable to type 'NumberTo<any>'.
101+
!!! error TS2322: Index signature is missing in type 'Obj'.
102+
103+
someObj = sToAny;
104+
~~~~~~~
105+
!!! error TS2322: Type 'StringTo<any>' is not assignable to type 'Obj'.
106+
someObj = nToAny;
107+
~~~~~~~
108+
!!! error TS2322: Type 'NumberTo<any>' is not assignable to type 'Obj'.
109+
someObj = bothToAny;
110+
~~~~~~~
111+
!!! error TS2739: Type 'StringTo<any> & NumberTo<any>' is missing the following properties from type 'Obj': hello, world
112+
}
113+
114+
type NumberToNumber = NumberTo<number>;
115+
116+
interface StringToAnyNumberToNumber extends StringTo<any>, NumberToNumber {
117+
}
118+
119+
function f3(sToAny: StringTo<any>, nToNumber: NumberToNumber, strToAnyNumToNum: StringToAnyNumberToNumber, someObj: Obj) {
120+
sToAny = nToNumber;
121+
sToAny = strToAnyNumToNum;
122+
sToAny = someObj;
123+
124+
nToNumber = sToAny;
125+
nToNumber = strToAnyNumToNum;
126+
nToNumber = someObj;
127+
~~~~~~~~~
128+
!!! error TS2322: Type 'Obj' is not assignable to type 'NumberToNumber'.
129+
!!! error TS2322: Index signature is missing in type 'Obj'.
130+
131+
strToAnyNumToNum = sToAny;
132+
strToAnyNumToNum = nToNumber;
133+
strToAnyNumToNum = someObj;
134+
~~~~~~~~~~~~~~~~
135+
!!! error TS2322: Type 'Obj' is not assignable to type 'StringToAnyNumberToNumber'.
136+
!!! error TS2322: Index signature is missing in type 'Obj'.
137+
138+
someObj = sToAny;
139+
~~~~~~~
140+
!!! error TS2322: Type 'StringTo<any>' is not assignable to type 'Obj'.
141+
someObj = nToNumber;
142+
~~~~~~~
143+
!!! error TS2739: Type 'NumberTo<number>' is missing the following properties from type 'Obj': hello, world
144+
someObj = someObj;
145+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//// [objectTypeWithStringAndNumberIndexSignatureToAny.ts]
2+
// When checking compatibility between two types,
3+
// TypeScript should not require an index signature if
4+
// the target side index signature maps to `any` *and*
5+
// the target side has *any* string index signature to `any`.
6+
//
7+
// So an index signature like in
8+
//
9+
// { [x: number]: any }
10+
//
11+
// is still required of a source type, but neither index signature in
12+
//
13+
// { [x: number]: any, [x: string]: any; }
14+
//
15+
// should be required; *however*, the number index signature in
16+
//
17+
// { [x: number]: number, [x: string]: any; }
18+
//
19+
// should always be required.
20+
21+
interface StringTo<T> {
22+
[x: string]: T;
23+
}
24+
25+
interface NumberTo<T> {
26+
[x: number]: T;
27+
}
28+
29+
interface StringAndNumberTo<T> extends StringTo<T>, NumberTo<T> {
30+
}
31+
32+
interface Obj {
33+
hello: string;
34+
world: number;
35+
}
36+
37+
function f1(sToAny: StringTo<any>, nToAny: NumberTo<any>, bothToAny: StringAndNumberTo<any>, someObj: Obj) {
38+
sToAny = nToAny;
39+
sToAny = bothToAny;
40+
sToAny = someObj;
41+
42+
nToAny = sToAny;
43+
nToAny = bothToAny;
44+
nToAny = someObj;
45+
46+
bothToAny = sToAny;
47+
bothToAny = nToAny;
48+
bothToAny = someObj;
49+
50+
someObj = sToAny;
51+
someObj = nToAny;
52+
someObj = bothToAny;
53+
}
54+
55+
function f2(sToAny: StringTo<any>, nToAny: NumberTo<any>, bothToAny: StringTo<any> & NumberTo<any>, someObj: Obj) {
56+
sToAny = nToAny;
57+
sToAny = bothToAny;
58+
sToAny = someObj;
59+
60+
nToAny = sToAny;
61+
nToAny = bothToAny;
62+
nToAny = someObj;
63+
64+
bothToAny = sToAny;
65+
bothToAny = nToAny;
66+
bothToAny = someObj;
67+
68+
someObj = sToAny;
69+
someObj = nToAny;
70+
someObj = bothToAny;
71+
}
72+
73+
type NumberToNumber = NumberTo<number>;
74+
75+
interface StringToAnyNumberToNumber extends StringTo<any>, NumberToNumber {
76+
}
77+
78+
function f3(sToAny: StringTo<any>, nToNumber: NumberToNumber, strToAnyNumToNum: StringToAnyNumberToNumber, someObj: Obj) {
79+
sToAny = nToNumber;
80+
sToAny = strToAnyNumToNum;
81+
sToAny = someObj;
82+
83+
nToNumber = sToAny;
84+
nToNumber = strToAnyNumToNum;
85+
nToNumber = someObj;
86+
87+
strToAnyNumToNum = sToAny;
88+
strToAnyNumToNum = nToNumber;
89+
strToAnyNumToNum = someObj;
90+
91+
someObj = sToAny;
92+
someObj = nToNumber;
93+
someObj = someObj;
94+
}
95+
96+
//// [objectTypeWithStringAndNumberIndexSignatureToAny.js]
97+
"use strict";
98+
// When checking compatibility between two types,
99+
// TypeScript should not require an index signature if
100+
// the target side index signature maps to `any` *and*
101+
// the target side has *any* string index signature to `any`.
102+
//
103+
// So an index signature like in
104+
//
105+
// { [x: number]: any }
106+
//
107+
// is still required of a source type, but neither index signature in
108+
//
109+
// { [x: number]: any, [x: string]: any; }
110+
//
111+
// should be required; *however*, the number index signature in
112+
//
113+
// { [x: number]: number, [x: string]: any; }
114+
//
115+
// should always be required.
116+
function f1(sToAny, nToAny, bothToAny, someObj) {
117+
sToAny = nToAny;
118+
sToAny = bothToAny;
119+
sToAny = someObj;
120+
nToAny = sToAny;
121+
nToAny = bothToAny;
122+
nToAny = someObj;
123+
bothToAny = sToAny;
124+
bothToAny = nToAny;
125+
bothToAny = someObj;
126+
someObj = sToAny;
127+
someObj = nToAny;
128+
someObj = bothToAny;
129+
}
130+
function f2(sToAny, nToAny, bothToAny, someObj) {
131+
sToAny = nToAny;
132+
sToAny = bothToAny;
133+
sToAny = someObj;
134+
nToAny = sToAny;
135+
nToAny = bothToAny;
136+
nToAny = someObj;
137+
bothToAny = sToAny;
138+
bothToAny = nToAny;
139+
bothToAny = someObj;
140+
someObj = sToAny;
141+
someObj = nToAny;
142+
someObj = bothToAny;
143+
}
144+
function f3(sToAny, nToNumber, strToAnyNumToNum, someObj) {
145+
sToAny = nToNumber;
146+
sToAny = strToAnyNumToNum;
147+
sToAny = someObj;
148+
nToNumber = sToAny;
149+
nToNumber = strToAnyNumToNum;
150+
nToNumber = someObj;
151+
strToAnyNumToNum = sToAny;
152+
strToAnyNumToNum = nToNumber;
153+
strToAnyNumToNum = someObj;
154+
someObj = sToAny;
155+
someObj = nToNumber;
156+
someObj = someObj;
157+
}

0 commit comments

Comments
 (0)