Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fa89ce6

Browse filesBrowse files
author
Orta Therox
authored
Remove assignability cases in getNarrowedType + an isArray improvement for readonly arrays (microsoft#39258)
* Explore using a different isArray declaration * Add tests and the new isArray definition * Baseline updates * Upda the isArray type
1 parent 1d2278b commit fa89ce6
Copy full SHA for fa89ce6

23 files changed

+700-63Lines changed: 700 additions & 63 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+5-9Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21984,15 +21984,11 @@ namespace ts {
2198421984
return assignableType;
2198521985
}
2198621986
}
21987-
// If the candidate type is a subtype of the target type, narrow to the candidate type.
21988-
// Otherwise, if the target type is assignable to the candidate type, keep the target type.
21989-
// Otherwise, if the candidate type is assignable to the target type, narrow to the candidate
21990-
// type. Otherwise, the types are completely unrelated, so narrow to an intersection of the
21991-
// two types.
21992-
return isTypeSubtypeOf(candidate, type) ? candidate :
21993-
isTypeAssignableTo(type, candidate) ? type :
21994-
isTypeAssignableTo(candidate, type) ? candidate :
21995-
getIntersectionType([type, candidate]);
21987+
21988+
// If the candidate type is a subtype of the target type, narrow to the candidate type,
21989+
// if the target type is a subtype of the candidate type, narrow to the target type,
21990+
// otherwise, narrow to an intersection of the two types.
21991+
return isTypeSubtypeOf(candidate, type) ? candidate : isTypeSubtypeOf(type, candidate) ? type : getIntersectionType([type, candidate]);
2199621992
}
2199721993

2199821994
function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
Collapse file

‎src/lib/es5.d.ts‎

Copy file name to clipboardExpand all lines: src/lib/es5.d.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,7 @@ interface ArrayConstructor {
13761376
(arrayLength?: number): any[];
13771377
<T>(arrayLength: number): T[];
13781378
<T>(...items: T[]): T[];
1379-
isArray(arg: any): arg is any[];
1379+
isArray<T>(arg: T | {}): arg is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[];
13801380
readonly prototype: any[];
13811381
}
13821382

Collapse file
+100Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//// [consistentUnionSubtypeReduction.ts]
2+
// https://github.com/microsoft/TypeScript/issues/31155
3+
4+
declare const MyArray: {
5+
isArray<T>(arg: T | {}): arg is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[];
6+
};
7+
8+
declare const a: readonly string[] | string;
9+
declare const b: string[] | string;
10+
declare const c: unknown;
11+
12+
if (MyArray.isArray(a)) {
13+
a; // readonly string[]
14+
}
15+
else {
16+
a; // string
17+
}
18+
a; // readonly string[] | string;
19+
20+
if (MyArray.isArray(b)) {
21+
b; // string[] | string;
22+
}
23+
else {
24+
b; // string
25+
}
26+
b; // string[] | string;
27+
28+
if (MyArray.isArray(c)) {
29+
c; // any[]
30+
}
31+
32+
33+
function f<T>(x: T) {
34+
const a: readonly T[] | string = null!;
35+
const b: T[] | string = null!;
36+
const c: T = null!;
37+
38+
if (MyArray.isArray(a)) {
39+
a; // readonly T[]
40+
}
41+
else {
42+
a; // string
43+
}
44+
a; // readonly T[] | string;
45+
46+
if (MyArray.isArray(b)) {
47+
b; // T[]
48+
}
49+
else {
50+
b; // string
51+
}
52+
b;
53+
54+
if (MyArray.isArray(c)) {
55+
c; // T & (T extends readonly any[] ? readonly any[] : any[])
56+
}
57+
}
58+
59+
60+
//// [consistentUnionSubtypeReduction.js]
61+
// https://github.com/microsoft/TypeScript/issues/31155
62+
if (MyArray.isArray(a)) {
63+
a; // readonly string[]
64+
}
65+
else {
66+
a; // string
67+
}
68+
a; // readonly string[] | string;
69+
if (MyArray.isArray(b)) {
70+
b; // string[] | string;
71+
}
72+
else {
73+
b; // string
74+
}
75+
b; // string[] | string;
76+
if (MyArray.isArray(c)) {
77+
c; // any[]
78+
}
79+
function f(x) {
80+
var a = null;
81+
var b = null;
82+
var c = null;
83+
if (MyArray.isArray(a)) {
84+
a; // readonly T[]
85+
}
86+
else {
87+
a; // string
88+
}
89+
a; // readonly T[] | string;
90+
if (MyArray.isArray(b)) {
91+
b; // T[]
92+
}
93+
else {
94+
b; // string
95+
}
96+
b;
97+
if (MyArray.isArray(c)) {
98+
c; // T & (T extends readonly any[] ? readonly any[] : any[])
99+
}
100+
}
Collapse file
+130Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
=== tests/cases/compiler/consistentUnionSubtypeReduction.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/31155
3+
4+
declare const MyArray: {
5+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
6+
7+
isArray<T>(arg: T | {}): arg is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[];
8+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
9+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 3, 12))
10+
>arg : Symbol(arg, Decl(consistentUnionSubtypeReduction.ts, 3, 15))
11+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 3, 12))
12+
>arg : Symbol(arg, Decl(consistentUnionSubtypeReduction.ts, 3, 15))
13+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 3, 12))
14+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 3, 12))
15+
16+
};
17+
18+
declare const a: readonly string[] | string;
19+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 6, 13))
20+
21+
declare const b: string[] | string;
22+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 7, 13))
23+
24+
declare const c: unknown;
25+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 8, 13))
26+
27+
if (MyArray.isArray(a)) {
28+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
29+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
30+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
31+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 6, 13))
32+
33+
a; // readonly string[]
34+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 6, 13))
35+
}
36+
else {
37+
a; // string
38+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 6, 13))
39+
}
40+
a; // readonly string[] | string;
41+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 6, 13))
42+
43+
if (MyArray.isArray(b)) {
44+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
45+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
46+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
47+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 7, 13))
48+
49+
b; // string[] | string;
50+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 7, 13))
51+
}
52+
else {
53+
b; // string
54+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 7, 13))
55+
}
56+
b; // string[] | string;
57+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 7, 13))
58+
59+
if (MyArray.isArray(c)) {
60+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
61+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
62+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
63+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 8, 13))
64+
65+
c; // any[]
66+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 8, 13))
67+
}
68+
69+
70+
function f<T>(x: T) {
71+
>f : Symbol(f, Decl(consistentUnionSubtypeReduction.ts, 28, 1))
72+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 31, 11))
73+
>x : Symbol(x, Decl(consistentUnionSubtypeReduction.ts, 31, 14))
74+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 31, 11))
75+
76+
const a: readonly T[] | string = null!;
77+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 32, 9))
78+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 31, 11))
79+
80+
const b: T[] | string = null!;
81+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 33, 9))
82+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 31, 11))
83+
84+
const c: T = null!;
85+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 34, 9))
86+
>T : Symbol(T, Decl(consistentUnionSubtypeReduction.ts, 31, 11))
87+
88+
if (MyArray.isArray(a)) {
89+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
90+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
91+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
92+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 32, 9))
93+
94+
a; // readonly T[]
95+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 32, 9))
96+
}
97+
else {
98+
a; // string
99+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 32, 9))
100+
}
101+
a; // readonly T[] | string;
102+
>a : Symbol(a, Decl(consistentUnionSubtypeReduction.ts, 32, 9))
103+
104+
if (MyArray.isArray(b)) {
105+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
106+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
107+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
108+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 33, 9))
109+
110+
b; // T[]
111+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 33, 9))
112+
}
113+
else {
114+
b; // string
115+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 33, 9))
116+
}
117+
b;
118+
>b : Symbol(b, Decl(consistentUnionSubtypeReduction.ts, 33, 9))
119+
120+
if (MyArray.isArray(c)) {
121+
>MyArray.isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
122+
>MyArray : Symbol(MyArray, Decl(consistentUnionSubtypeReduction.ts, 2, 13))
123+
>isArray : Symbol(isArray, Decl(consistentUnionSubtypeReduction.ts, 2, 24))
124+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 34, 9))
125+
126+
c; // T & (T extends readonly any[] ? readonly any[] : any[])
127+
>c : Symbol(c, Decl(consistentUnionSubtypeReduction.ts, 34, 9))
128+
}
129+
}
130+
Collapse file
+132Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
=== tests/cases/compiler/consistentUnionSubtypeReduction.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/31155
3+
4+
declare const MyArray: {
5+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
6+
7+
isArray<T>(arg: T | {}): arg is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[];
8+
>isArray : <T>(arg: T | {}) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
9+
>arg : {} | T
10+
11+
};
12+
13+
declare const a: readonly string[] | string;
14+
>a : string | readonly string[]
15+
16+
declare const b: string[] | string;
17+
>b : string | string[]
18+
19+
declare const c: unknown;
20+
>c : unknown
21+
22+
if (MyArray.isArray(a)) {
23+
>MyArray.isArray(a) : boolean
24+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
25+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
26+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
27+
>a : string | readonly string[]
28+
29+
a; // readonly string[]
30+
>a : readonly string[]
31+
}
32+
else {
33+
a; // string
34+
>a : string
35+
}
36+
a; // readonly string[] | string;
37+
>a : string | readonly string[]
38+
39+
if (MyArray.isArray(b)) {
40+
>MyArray.isArray(b) : boolean
41+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
42+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
43+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
44+
>b : string | string[]
45+
46+
b; // string[] | string;
47+
>b : string[]
48+
}
49+
else {
50+
b; // string
51+
>b : string
52+
}
53+
b; // string[] | string;
54+
>b : string | string[]
55+
56+
if (MyArray.isArray(c)) {
57+
>MyArray.isArray(c) : boolean
58+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
59+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
60+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
61+
>c : unknown
62+
63+
c; // any[]
64+
>c : any[]
65+
}
66+
67+
68+
function f<T>(x: T) {
69+
>f : <T>(x: T) => void
70+
>x : T
71+
72+
const a: readonly T[] | string = null!;
73+
>a : string | readonly T[]
74+
>null! : null
75+
>null : null
76+
77+
const b: T[] | string = null!;
78+
>b : string | T[]
79+
>null! : null
80+
>null : null
81+
82+
const c: T = null!;
83+
>c : T
84+
>null! : null
85+
>null : null
86+
87+
if (MyArray.isArray(a)) {
88+
>MyArray.isArray(a) : boolean
89+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
90+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
91+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
92+
>a : string | readonly T[]
93+
94+
a; // readonly T[]
95+
>a : readonly T[]
96+
}
97+
else {
98+
a; // string
99+
>a : string
100+
}
101+
a; // readonly T[] | string;
102+
>a : string | readonly T[]
103+
104+
if (MyArray.isArray(b)) {
105+
>MyArray.isArray(b) : boolean
106+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
107+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
108+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
109+
>b : string | T[]
110+
111+
b; // T[]
112+
>b : T[]
113+
}
114+
else {
115+
b; // string
116+
>b : string
117+
}
118+
b;
119+
>b : string | T[]
120+
121+
if (MyArray.isArray(c)) {
122+
>MyArray.isArray(c) : boolean
123+
>MyArray.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
124+
>MyArray : { isArray<T>(arg: {} | T): arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]; }
125+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
126+
>c : T
127+
128+
c; // T & (T extends readonly any[] ? readonly any[] : any[])
129+
>c : T & (T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[])
130+
}
131+
}
132+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.