Skip to content

Commit 24542b8

Browse files
committed
Adds a test for the change
1 parent 4548c6f commit 24542b8

4 files changed

+380
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//// [narrowingAssignmentReadonlyRespectsAssertion.ts]
2+
// https://github.com/microsoft/TypeScript/issues/41984
3+
4+
interface TestCase<T extends string | number> {
5+
readonly val1: T | ReadonlyArray<T>;
6+
readonly val2: ReadonlyArray<T>;
7+
}
8+
9+
interface MultiCaseFixture<T> {
10+
cases: T[];
11+
}
12+
13+
function subDataFunc(): TestCase<string | number>[] {
14+
return [
15+
{ val1: "a", val2: ["a", "b", "c"] },
16+
{ val1: 2, val2: [1, 2, 3] },
17+
{ val1: ["a", "z"], val2: ["x", "y", "z"] },
18+
{ val1: [5, 10], val2: [10, 100, 1000] },
19+
];
20+
}
21+
22+
function dataFunc<T>(subFunc: () => T[]): MultiCaseFixture<T> {
23+
return { cases: subFunc() };
24+
}
25+
26+
function testFunc() {
27+
const fixture = dataFunc<TestCase<string | number>>(subDataFunc);
28+
fixture.cases.forEach(({ val1, val2 }) => {
29+
if (Array.isArray(val1)) {
30+
// This should retain val1 as being an array
31+
const reversedVal1 = val1.slice().reverse();
32+
console.log(reversedVal1);
33+
} else {
34+
console.log(val1);
35+
}
36+
console.log(val2);
37+
});
38+
}
39+
40+
testFunc();
41+
42+
43+
//// [narrowingAssignmentReadonlyRespectsAssertion.js]
44+
// https://github.com/microsoft/TypeScript/issues/41984
45+
function subDataFunc() {
46+
return [
47+
{ val1: "a", val2: ["a", "b", "c"] },
48+
{ val1: 2, val2: [1, 2, 3] },
49+
{ val1: ["a", "z"], val2: ["x", "y", "z"] },
50+
{ val1: [5, 10], val2: [10, 100, 1000] },
51+
];
52+
}
53+
function dataFunc(subFunc) {
54+
return { cases: subFunc() };
55+
}
56+
function testFunc() {
57+
var fixture = dataFunc(subDataFunc);
58+
fixture.cases.forEach(function (_a) {
59+
var val1 = _a.val1, val2 = _a.val2;
60+
if (Array.isArray(val1)) {
61+
// This should retain val1 as being an array
62+
var reversedVal1 = val1.slice().reverse();
63+
console.log(reversedVal1);
64+
}
65+
else {
66+
console.log(val1);
67+
}
68+
console.log(val2);
69+
});
70+
}
71+
testFunc();
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
=== tests/cases/compiler/narrowingAssignmentReadonlyRespectsAssertion.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/41984
3+
4+
interface TestCase<T extends string | number> {
5+
>TestCase : Symbol(TestCase, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 0, 0))
6+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 2, 19))
7+
8+
readonly val1: T | ReadonlyArray<T>;
9+
>val1 : Symbol(TestCase.val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 2, 47))
10+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 2, 19))
11+
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
12+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 2, 19))
13+
14+
readonly val2: ReadonlyArray<T>;
15+
>val2 : Symbol(TestCase.val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 3, 38))
16+
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
17+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 2, 19))
18+
}
19+
20+
interface MultiCaseFixture<T> {
21+
>MultiCaseFixture : Symbol(MultiCaseFixture, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 5, 1))
22+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 7, 27))
23+
24+
cases: T[];
25+
>cases : Symbol(MultiCaseFixture.cases, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 7, 31))
26+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 7, 27))
27+
}
28+
29+
function subDataFunc(): TestCase<string | number>[] {
30+
>subDataFunc : Symbol(subDataFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 9, 1))
31+
>TestCase : Symbol(TestCase, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 0, 0))
32+
33+
return [
34+
{ val1: "a", val2: ["a", "b", "c"] },
35+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 13, 7))
36+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 13, 18))
37+
38+
{ val1: 2, val2: [1, 2, 3] },
39+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 14, 7))
40+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 14, 16))
41+
42+
{ val1: ["a", "z"], val2: ["x", "y", "z"] },
43+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 15, 7))
44+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 15, 25))
45+
46+
{ val1: [5, 10], val2: [10, 100, 1000] },
47+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 16, 7))
48+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 16, 22))
49+
50+
];
51+
}
52+
53+
function dataFunc<T>(subFunc: () => T[]): MultiCaseFixture<T> {
54+
>dataFunc : Symbol(dataFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 18, 1))
55+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 20, 18))
56+
>subFunc : Symbol(subFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 20, 21))
57+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 20, 18))
58+
>MultiCaseFixture : Symbol(MultiCaseFixture, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 5, 1))
59+
>T : Symbol(T, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 20, 18))
60+
61+
return { cases: subFunc() };
62+
>cases : Symbol(cases, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 21, 10))
63+
>subFunc : Symbol(subFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 20, 21))
64+
}
65+
66+
function testFunc() {
67+
>testFunc : Symbol(testFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 22, 1))
68+
69+
const fixture = dataFunc<TestCase<string | number>>(subDataFunc);
70+
>fixture : Symbol(fixture, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 25, 7))
71+
>dataFunc : Symbol(dataFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 18, 1))
72+
>TestCase : Symbol(TestCase, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 0, 0))
73+
>subDataFunc : Symbol(subDataFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 9, 1))
74+
75+
fixture.cases.forEach(({ val1, val2 }) => {
76+
>fixture.cases.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
77+
>fixture.cases : Symbol(MultiCaseFixture.cases, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 7, 31))
78+
>fixture : Symbol(fixture, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 25, 7))
79+
>cases : Symbol(MultiCaseFixture.cases, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 7, 31))
80+
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
81+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 26))
82+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 32))
83+
84+
if (Array.isArray(val1)) {
85+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
86+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
87+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
88+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 26))
89+
90+
// This should retain val1 as being an array
91+
const reversedVal1 = val1.slice().reverse();
92+
>reversedVal1 : Symbol(reversedVal1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 29, 15))
93+
>val1.slice().reverse : Symbol(Array.reverse, Decl(lib.es5.d.ts, --, --))
94+
>val1.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))
95+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 26))
96+
>slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))
97+
>reverse : Symbol(Array.reverse, Decl(lib.es5.d.ts, --, --))
98+
99+
console.log(reversedVal1);
100+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
101+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
102+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
103+
>reversedVal1 : Symbol(reversedVal1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 29, 15))
104+
105+
} else {
106+
console.log(val1);
107+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
108+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
109+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
110+
>val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 26))
111+
}
112+
console.log(val2);
113+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
114+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
115+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
116+
>val2 : Symbol(val2, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 32))
117+
118+
});
119+
}
120+
121+
testFunc();
122+
>testFunc : Symbol(testFunc, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 22, 1))
123+
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
=== tests/cases/compiler/narrowingAssignmentReadonlyRespectsAssertion.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/41984
3+
4+
interface TestCase<T extends string | number> {
5+
readonly val1: T | ReadonlyArray<T>;
6+
>val1 : T | readonly T[]
7+
8+
readonly val2: ReadonlyArray<T>;
9+
>val2 : readonly T[]
10+
}
11+
12+
interface MultiCaseFixture<T> {
13+
cases: T[];
14+
>cases : T[]
15+
}
16+
17+
function subDataFunc(): TestCase<string | number>[] {
18+
>subDataFunc : () => TestCase<string | number>[]
19+
20+
return [
21+
>[ { val1: "a", val2: ["a", "b", "c"] }, { val1: 2, val2: [1, 2, 3] }, { val1: ["a", "z"], val2: ["x", "y", "z"] }, { val1: [5, 10], val2: [10, 100, 1000] }, ] : ({ val1: string; val2: string[]; } | { val1: number; val2: number[]; } | { val1: string[]; val2: string[]; } | { val1: number[]; val2: number[]; })[]
22+
23+
{ val1: "a", val2: ["a", "b", "c"] },
24+
>{ val1: "a", val2: ["a", "b", "c"] } : { val1: string; val2: string[]; }
25+
>val1 : string
26+
>"a" : "a"
27+
>val2 : string[]
28+
>["a", "b", "c"] : string[]
29+
>"a" : "a"
30+
>"b" : "b"
31+
>"c" : "c"
32+
33+
{ val1: 2, val2: [1, 2, 3] },
34+
>{ val1: 2, val2: [1, 2, 3] } : { val1: number; val2: number[]; }
35+
>val1 : number
36+
>2 : 2
37+
>val2 : number[]
38+
>[1, 2, 3] : number[]
39+
>1 : 1
40+
>2 : 2
41+
>3 : 3
42+
43+
{ val1: ["a", "z"], val2: ["x", "y", "z"] },
44+
>{ val1: ["a", "z"], val2: ["x", "y", "z"] } : { val1: string[]; val2: string[]; }
45+
>val1 : string[]
46+
>["a", "z"] : string[]
47+
>"a" : "a"
48+
>"z" : "z"
49+
>val2 : string[]
50+
>["x", "y", "z"] : string[]
51+
>"x" : "x"
52+
>"y" : "y"
53+
>"z" : "z"
54+
55+
{ val1: [5, 10], val2: [10, 100, 1000] },
56+
>{ val1: [5, 10], val2: [10, 100, 1000] } : { val1: number[]; val2: number[]; }
57+
>val1 : number[]
58+
>[5, 10] : number[]
59+
>5 : 5
60+
>10 : 10
61+
>val2 : number[]
62+
>[10, 100, 1000] : number[]
63+
>10 : 10
64+
>100 : 100
65+
>1000 : 1000
66+
67+
];
68+
}
69+
70+
function dataFunc<T>(subFunc: () => T[]): MultiCaseFixture<T> {
71+
>dataFunc : <T>(subFunc: () => T[]) => MultiCaseFixture<T>
72+
>subFunc : () => T[]
73+
74+
return { cases: subFunc() };
75+
>{ cases: subFunc() } : { cases: T[]; }
76+
>cases : T[]
77+
>subFunc() : T[]
78+
>subFunc : () => T[]
79+
}
80+
81+
function testFunc() {
82+
>testFunc : () => void
83+
84+
const fixture = dataFunc<TestCase<string | number>>(subDataFunc);
85+
>fixture : MultiCaseFixture<TestCase<string | number>>
86+
>dataFunc<TestCase<string | number>>(subDataFunc) : MultiCaseFixture<TestCase<string | number>>
87+
>dataFunc : <T>(subFunc: () => T[]) => MultiCaseFixture<T>
88+
>subDataFunc : () => TestCase<string | number>[]
89+
90+
fixture.cases.forEach(({ val1, val2 }) => {
91+
>fixture.cases.forEach(({ val1, val2 }) => { if (Array.isArray(val1)) { // This should retain val1 as being an array const reversedVal1 = val1.slice().reverse(); console.log(reversedVal1); } else { console.log(val1); } console.log(val2); }) : void
92+
>fixture.cases.forEach : (callbackfn: (value: TestCase<string | number>, index: number, array: TestCase<string | number>[]) => void, thisArg?: any) => void
93+
>fixture.cases : TestCase<string | number>[]
94+
>fixture : MultiCaseFixture<TestCase<string | number>>
95+
>cases : TestCase<string | number>[]
96+
>forEach : (callbackfn: (value: TestCase<string | number>, index: number, array: TestCase<string | number>[]) => void, thisArg?: any) => void
97+
>({ val1, val2 }) => { if (Array.isArray(val1)) { // This should retain val1 as being an array const reversedVal1 = val1.slice().reverse(); console.log(reversedVal1); } else { console.log(val1); } console.log(val2); } : ({ val1, val2 }: TestCase<string | number>) => void
98+
>val1 : string | number | readonly (string | number)[]
99+
>val2 : readonly (string | number)[]
100+
101+
if (Array.isArray(val1)) {
102+
>Array.isArray(val1) : boolean
103+
>Array.isArray : (arg: any) => arg is any[]
104+
>Array : ArrayConstructor
105+
>isArray : (arg: any) => arg is any[]
106+
>val1 : string | number | readonly (string | number)[]
107+
108+
// This should retain val1 as being an array
109+
const reversedVal1 = val1.slice().reverse();
110+
>reversedVal1 : any[]
111+
>val1.slice().reverse() : any[]
112+
>val1.slice().reverse : () => any[]
113+
>val1.slice() : any[]
114+
>val1.slice : (start?: number, end?: number) => any[]
115+
>val1 : any[]
116+
>slice : (start?: number, end?: number) => any[]
117+
>reverse : () => any[]
118+
119+
console.log(reversedVal1);
120+
>console.log(reversedVal1) : void
121+
>console.log : (...data: any[]) => void
122+
>console : Console
123+
>log : (...data: any[]) => void
124+
>reversedVal1 : any[]
125+
126+
} else {
127+
console.log(val1);
128+
>console.log(val1) : void
129+
>console.log : (...data: any[]) => void
130+
>console : Console
131+
>log : (...data: any[]) => void
132+
>val1 : string | number | readonly (string | number)[]
133+
}
134+
console.log(val2);
135+
>console.log(val2) : void
136+
>console.log : (...data: any[]) => void
137+
>console : Console
138+
>log : (...data: any[]) => void
139+
>val2 : readonly (string | number)[]
140+
141+
});
142+
}
143+
144+
testFunc();
145+
>testFunc() : void
146+
>testFunc : () => void
147+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// https://github.com/microsoft/TypeScript/issues/41984
2+
3+
interface TestCase<T extends string | number> {
4+
readonly val1: T | ReadonlyArray<T>;
5+
readonly val2: ReadonlyArray<T>;
6+
}
7+
8+
interface MultiCaseFixture<T> {
9+
cases: T[];
10+
}
11+
12+
function subDataFunc(): TestCase<string | number>[] {
13+
return [
14+
{ val1: "a", val2: ["a", "b", "c"] },
15+
{ val1: 2, val2: [1, 2, 3] },
16+
{ val1: ["a", "z"], val2: ["x", "y", "z"] },
17+
{ val1: [5, 10], val2: [10, 100, 1000] },
18+
];
19+
}
20+
21+
function dataFunc<T>(subFunc: () => T[]): MultiCaseFixture<T> {
22+
return { cases: subFunc() };
23+
}
24+
25+
function testFunc() {
26+
const fixture = dataFunc<TestCase<string | number>>(subDataFunc);
27+
fixture.cases.forEach(({ val1, val2 }) => {
28+
if (Array.isArray(val1)) {
29+
// This should retain val1 as being an array
30+
const reversedVal1 = val1.slice().reverse();
31+
console.log(reversedVal1);
32+
} else {
33+
console.log(val1);
34+
}
35+
console.log(val2);
36+
});
37+
}
38+
39+
testFunc();

0 commit comments

Comments
 (0)