Skip to content

Commit df5ffc0

Browse files
Remove special any assignability for numeric index signatures (#41660)
* Only enable special assignability rule on string index signatures to 'any'. * Accepted baselines. * Added test. * Accepted baselines. * Renamed test files. * Add non-erroring version of bclas'subClassThisTypeAssignable01.ts' * Accepted baselines. Co-authored-by: TypeScript Bot <[email protected]>
1 parent 2c5cee5 commit df5ffc0

20 files changed

+392
-36
lines changed

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18948,7 +18948,7 @@ namespace ts {
1894818948
return indexTypesIdenticalTo(source, target, kind);
1894918949
}
1895018950
const targetType = getIndexTypeOfType(target, kind);
18951-
if (!targetType || targetType.flags & TypeFlags.Any && !sourceIsPrimitive) {
18951+
if (!targetType || targetType.flags & TypeFlags.Any && !sourceIsPrimitive && kind === IndexKind.String) {
1895218952
// Index signature of type any permits assignment from everything but primitives
1895318953
return Ternary.True;
1895418954
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/compiler/functionAssignabilityWithArrayLike01.ts(2,7): error TS2322: Type '() => void' is not assignable to type 'ArrayLike<any>'.
2+
Index signature is missing in type '() => void'.
3+
4+
5+
==== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts (1 errors) ====
6+
function func() {}
7+
const array: ArrayLike<any> = func;
8+
~~~~~
9+
!!! error TS2322: Type '() => void' is not assignable to type 'ArrayLike<any>'.
10+
!!! error TS2322: Index signature is missing in type '() => void'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [functionAssignabilityWithArrayLike01.ts]
2+
function func() {}
3+
const array: ArrayLike<any> = func;
4+
5+
//// [functionAssignabilityWithArrayLike01.js]
6+
function func() { }
7+
var array = func;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts ===
2+
function func() {}
3+
>func : Symbol(func, Decl(functionAssignabilityWithArrayLike01.ts, 0, 0))
4+
5+
const array: ArrayLike<any> = func;
6+
>array : Symbol(array, Decl(functionAssignabilityWithArrayLike01.ts, 1, 5))
7+
>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
8+
>func : Symbol(func, Decl(functionAssignabilityWithArrayLike01.ts, 0, 0))
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts ===
2+
function func() {}
3+
>func : () => void
4+
5+
const array: ArrayLike<any> = func;
6+
>array : ArrayLike<any>
7+
>func : () => void
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/compiler/functionAssignabilityWithArrayLike01.ts(2,7): error TS2322: Type '() => void' is not assignable to type 'ArrayLike<any>'.
2+
Index signature is missing in type '() => void'.
3+
4+
5+
==== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts (1 errors) ====
6+
function func() {}
7+
const array: ArrayLike<any> = func;
8+
~~~~~
9+
!!! error TS2322: Type '() => void' is not assignable to type 'ArrayLike<any>'.
10+
!!! error TS2322: Index signature is missing in type '() => void'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [functionAssignabilityWithArrayLike01.ts]
2+
function func() {}
3+
const array: ArrayLike<any> = func;
4+
5+
//// [functionAssignabilityWithArrayLike01.js]
6+
"use strict";
7+
function func() { }
8+
var array = func;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts ===
2+
function func() {}
3+
>func : Symbol(func, Decl(functionAssignabilityWithArrayLike01.ts, 0, 0))
4+
5+
const array: ArrayLike<any> = func;
6+
>array : Symbol(array, Decl(functionAssignabilityWithArrayLike01.ts, 1, 5))
7+
>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --))
8+
>func : Symbol(func, Decl(functionAssignabilityWithArrayLike01.ts, 0, 0))
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/compiler/functionAssignabilityWithArrayLike01.ts ===
2+
function func() {}
3+
>func : () => void
4+
5+
const array: ArrayLike<any> = func;
6+
>array : ArrayLike<any>
7+
>func : () => void
8+

tests/baselines/reference/subclassThisTypeAssignable.errors.txt

-34
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
tests/cases/compiler/file1.js(2,7): error TS2322: Type 'C' is not assignable to type 'ClassComponent<any>'.
2+
tests/cases/compiler/tile1.ts(2,30): error TS2344: Type 'State' does not satisfy the constraint 'Lifecycle<Attrs, State>'.
3+
tests/cases/compiler/tile1.ts(6,81): error TS2744: Type parameter defaults can only reference previously declared type parameters.
4+
tests/cases/compiler/tile1.ts(11,40): error TS2344: Type 'State' does not satisfy the constraint 'Lifecycle<Attrs, State>'.
5+
tests/cases/compiler/tile1.ts(21,2): error TS2416: Property 'view' in type 'C' is not assignable to the same property in base type 'ClassComponent<MyAttrs>'.
6+
Type '(v: Vnode<MyAttrs, Lifecycle<MyAttrs, any>>) => number' is not assignable to type '(vnode: Vnode<MyAttrs, this>) => number'.
7+
Types of parameters 'v' and 'vnode' are incompatible.
8+
Type 'Vnode<MyAttrs, this>' is not assignable to type 'Vnode<MyAttrs, Lifecycle<MyAttrs, any>>'.
9+
Type 'this' is not assignable to type 'Lifecycle<MyAttrs, any>'.
10+
Type 'C' is not assignable to type 'Lifecycle<MyAttrs, any>'.
11+
Index signature is missing in type 'C'.
12+
tests/cases/compiler/tile1.ts(24,7): error TS2322: Type 'C' is not assignable to type 'ClassComponent<any>'.
13+
Index signature is missing in type 'C'.
14+
15+
16+
==== tests/cases/compiler/tile1.ts (5 errors) ====
17+
interface Lifecycle<Attrs, State> {
18+
oninit?(vnode: Vnode<Attrs, State>): number;
19+
~~~~~
20+
!!! error TS2344: Type 'State' does not satisfy the constraint 'Lifecycle<Attrs, State>'.
21+
[_: number]: any;
22+
}
23+
24+
interface Vnode<Attrs, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> {
25+
~~~~~
26+
!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
27+
tag: Component<Attrs, State>;
28+
}
29+
30+
interface Component<Attrs, State> {
31+
view(this: State, vnode: Vnode<Attrs, State>): number;
32+
~~~~~
33+
!!! error TS2344: Type 'State' does not satisfy the constraint 'Lifecycle<Attrs, State>'.
34+
}
35+
36+
interface ClassComponent<A> extends Lifecycle<A, ClassComponent<A>> {
37+
oninit?(vnode: Vnode<A, this>): number;
38+
view(vnode: Vnode<A, this>): number;
39+
}
40+
41+
interface MyAttrs { id: number }
42+
class C implements ClassComponent<MyAttrs> {
43+
view(v: Vnode<MyAttrs>) { return 0; }
44+
~~~~
45+
!!! error TS2416: Property 'view' in type 'C' is not assignable to the same property in base type 'ClassComponent<MyAttrs>'.
46+
!!! error TS2416: Type '(v: Vnode<MyAttrs, Lifecycle<MyAttrs, any>>) => number' is not assignable to type '(vnode: Vnode<MyAttrs, this>) => number'.
47+
!!! error TS2416: Types of parameters 'v' and 'vnode' are incompatible.
48+
!!! error TS2416: Type 'Vnode<MyAttrs, this>' is not assignable to type 'Vnode<MyAttrs, Lifecycle<MyAttrs, any>>'.
49+
!!! error TS2416: Type 'this' is not assignable to type 'Lifecycle<MyAttrs, any>'.
50+
!!! error TS2416: Type 'C' is not assignable to type 'Lifecycle<MyAttrs, any>'.
51+
!!! error TS2416: Index signature is missing in type 'C'.
52+
}
53+
54+
const test8: ClassComponent<any> = new C();
55+
~~~~~
56+
!!! error TS2322: Type 'C' is not assignable to type 'ClassComponent<any>'.
57+
!!! error TS2322: Index signature is missing in type 'C'.
58+
==== tests/cases/compiler/file1.js (1 errors) ====
59+
/** @type {ClassComponent<any>} */
60+
const test9 = new C();
61+
~~~~~
62+
!!! error TS2322: Type 'C' is not assignable to type 'ClassComponent<any>'.
63+

tests/baselines/reference/subclassThisTypeAssignable.js renamed to tests/baselines/reference/subclassThisTypeAssignable01.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//// [tests/cases/compiler/subclassThisTypeAssignable.ts] ////
1+
//// [tests/cases/compiler/subclassThisTypeAssignable01.ts] ////
22

33
//// [tile1.ts]
44
interface Lifecycle<Attrs, State> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [tests/cases/compiler/subclassThisTypeAssignable02.ts] ////
2+
3+
//// [tile1.ts]
4+
interface Lifecycle<Attrs, State extends Lifecycle<Attrs, State>> {
5+
oninit?(vnode: Vnode<Attrs, State>): number;
6+
[_: number]: any;
7+
}
8+
9+
interface Vnode<Attrs, State extends Lifecycle<Attrs, State>> {
10+
tag: Component<Attrs, State>;
11+
}
12+
13+
interface Component<Attrs, State extends Lifecycle<Attrs, State>> {
14+
view(this: State, vnode: Vnode<Attrs, State>): number;
15+
}
16+
17+
interface ClassComponent<A> extends Lifecycle<A, ClassComponent<A>> {
18+
oninit?(vnode: Vnode<A, this>): number;
19+
view(vnode: Vnode<A, this>): number;
20+
}
21+
22+
interface MyAttrs { id: number }
23+
class C implements ClassComponent<MyAttrs> {
24+
view(v: Vnode<MyAttrs, C>) { return 0; }
25+
26+
// Must declare a compatible-ish index signature or else
27+
// we won't correctly implement ClassComponent.
28+
[_: number]: unknown;
29+
}
30+
31+
const test8: ClassComponent<any> = new C();
32+
//// [file1.js]
33+
/** @type {ClassComponent<any>} */
34+
const test9 = new C();
35+
36+
37+
//// [tile1.js]
38+
"use strict";
39+
var C = /** @class */ (function () {
40+
function C() {
41+
}
42+
C.prototype.view = function (v) { return 0; };
43+
return C;
44+
}());
45+
var test8 = new C();
46+
//// [file1.js]
47+
"use strict";
48+
/** @type {ClassComponent<any>} */
49+
var test9 = new C();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
=== tests/cases/compiler/tile1.ts ===
2+
interface Lifecycle<Attrs, State extends Lifecycle<Attrs, State>> {
3+
>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0))
4+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 0, 20))
5+
>State : Symbol(State, Decl(tile1.ts, 0, 26))
6+
>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0))
7+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 0, 20))
8+
>State : Symbol(State, Decl(tile1.ts, 0, 26))
9+
10+
oninit?(vnode: Vnode<Attrs, State>): number;
11+
>oninit : Symbol(Lifecycle.oninit, Decl(tile1.ts, 0, 67))
12+
>vnode : Symbol(vnode, Decl(tile1.ts, 1, 9))
13+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
14+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 0, 20))
15+
>State : Symbol(State, Decl(tile1.ts, 0, 26))
16+
17+
[_: number]: any;
18+
>_ : Symbol(_, Decl(tile1.ts, 2, 2))
19+
}
20+
21+
interface Vnode<Attrs, State extends Lifecycle<Attrs, State>> {
22+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
23+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16))
24+
>State : Symbol(State, Decl(tile1.ts, 5, 22))
25+
>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0))
26+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16))
27+
>State : Symbol(State, Decl(tile1.ts, 5, 22))
28+
29+
tag: Component<Attrs, State>;
30+
>tag : Symbol(Vnode.tag, Decl(tile1.ts, 5, 63))
31+
>Component : Symbol(Component, Decl(tile1.ts, 7, 1))
32+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 5, 16))
33+
>State : Symbol(State, Decl(tile1.ts, 5, 22))
34+
}
35+
36+
interface Component<Attrs, State extends Lifecycle<Attrs, State>> {
37+
>Component : Symbol(Component, Decl(tile1.ts, 7, 1))
38+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 9, 20))
39+
>State : Symbol(State, Decl(tile1.ts, 9, 26))
40+
>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0))
41+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 9, 20))
42+
>State : Symbol(State, Decl(tile1.ts, 9, 26))
43+
44+
view(this: State, vnode: Vnode<Attrs, State>): number;
45+
>view : Symbol(Component.view, Decl(tile1.ts, 9, 67))
46+
>this : Symbol(this, Decl(tile1.ts, 10, 6))
47+
>State : Symbol(State, Decl(tile1.ts, 9, 26))
48+
>vnode : Symbol(vnode, Decl(tile1.ts, 10, 18))
49+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
50+
>Attrs : Symbol(Attrs, Decl(tile1.ts, 9, 20))
51+
>State : Symbol(State, Decl(tile1.ts, 9, 26))
52+
}
53+
54+
interface ClassComponent<A> extends Lifecycle<A, ClassComponent<A>> {
55+
>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1))
56+
>A : Symbol(A, Decl(tile1.ts, 13, 25))
57+
>Lifecycle : Symbol(Lifecycle, Decl(tile1.ts, 0, 0))
58+
>A : Symbol(A, Decl(tile1.ts, 13, 25))
59+
>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1))
60+
>A : Symbol(A, Decl(tile1.ts, 13, 25))
61+
62+
oninit?(vnode: Vnode<A, this>): number;
63+
>oninit : Symbol(ClassComponent.oninit, Decl(tile1.ts, 13, 69))
64+
>vnode : Symbol(vnode, Decl(tile1.ts, 14, 9))
65+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
66+
>A : Symbol(A, Decl(tile1.ts, 13, 25))
67+
68+
view(vnode: Vnode<A, this>): number;
69+
>view : Symbol(ClassComponent.view, Decl(tile1.ts, 14, 40))
70+
>vnode : Symbol(vnode, Decl(tile1.ts, 15, 6))
71+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
72+
>A : Symbol(A, Decl(tile1.ts, 13, 25))
73+
}
74+
75+
interface MyAttrs { id: number }
76+
>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1))
77+
>id : Symbol(MyAttrs.id, Decl(tile1.ts, 18, 19))
78+
79+
class C implements ClassComponent<MyAttrs> {
80+
>C : Symbol(C, Decl(tile1.ts, 18, 32))
81+
>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1))
82+
>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1))
83+
84+
view(v: Vnode<MyAttrs, C>) { return 0; }
85+
>view : Symbol(C.view, Decl(tile1.ts, 19, 44))
86+
>v : Symbol(v, Decl(tile1.ts, 20, 6))
87+
>Vnode : Symbol(Vnode, Decl(tile1.ts, 3, 1))
88+
>MyAttrs : Symbol(MyAttrs, Decl(tile1.ts, 16, 1))
89+
>C : Symbol(C, Decl(tile1.ts, 18, 32))
90+
91+
// Must declare a compatible-ish index signature or else
92+
// we won't correctly implement ClassComponent.
93+
[_: number]: unknown;
94+
>_ : Symbol(_, Decl(tile1.ts, 24, 2))
95+
}
96+
97+
const test8: ClassComponent<any> = new C();
98+
>test8 : Symbol(test8, Decl(tile1.ts, 27, 5))
99+
>ClassComponent : Symbol(ClassComponent, Decl(tile1.ts, 11, 1))
100+
>C : Symbol(C, Decl(tile1.ts, 18, 32))
101+
102+
=== tests/cases/compiler/file1.js ===
103+
/** @type {ClassComponent<any>} */
104+
const test9 = new C();
105+
>test9 : Symbol(test9, Decl(file1.js, 1, 5))
106+
>C : Symbol(C, Decl(tile1.ts, 18, 32))
107+

0 commit comments

Comments
 (0)