-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Description
Bug Report
Search Terms: type assertion, type comparison, related to, generic parameter
Version & Regression Information: This changed between versions 4.7 and 4.8
Code: Playground Link
I discovered this issue in my PR #50454 when I am looking for a possible solution to the typing of Array.isArray
.
Consider the following code:
declare function f0<T>(arg: T): arg is Extract<T, readonly any[]>;
declare function f1<T>(arg: T): arg is Extract<T, any[]>;
declare function f2<T>(arg: T): arg is {} extends T ? T & any[] : Extract<T, readonly any[]>;
declare function f3<T>(arg: T): arg is {} extends T ? T & any[] : Extract<T, any[]>;
declare function f4<T>(arg: T): arg is T extends any ? {} extends T ? T & any[] : Extract<T, readonly any[]> : never;
declare function f5<T>(arg: T): arg is T extends any ? {} extends T ? T & any[] : Extract<T, any[]> : never;
declare function f6<T>(arg: T): arg is T extends any ? Extract<T, readonly any[]> : never;
declare function f7<T>(arg: T): arg is T extends any ? Extract<T, any[]> : never;
declare function f8<T>(arg: T): arg is T extends readonly any[] ? T : never;
declare function f9<T>(arg: T): arg is T extends any[] ? T : never;
declare function fa<T>(arg: T): arg is {} extends T ? T & any[] : T extends readonly any[] ? T : never;
declare function fb<T>(arg: T): arg is {} extends T ? T & any[] : T extends any[] ? T : never;
declare function fc<T>(arg: T): arg is T extends any ? {} extends T ? T & any[] : T extends readonly any[] ? T : never : never;
declare function fd<T>(arg: T): arg is T extends any ? {} extends T ? T & any[] : T extends any[] ? T : never : never;
declare function fe<T>(arg: T): arg is T extends any ? T extends readonly any[] ? T : never : never;
declare function ff<T>(arg: T): arg is T extends any ? T extends any[] ? T : never : never;
function case1<T extends any>(a: T | T[]): T[] {
return f(a) ? a : [a];
}
function case2<T extends unknown>(a: T | T[]): T[] {
return f(a) ? a : [a];
}
function case3<T>(a: T | T[]): T[] {
return f(a) ? a : [a];
}
In the above, f4
is the simplified version of the type I used in the PR.
Actual behavior:
From 4.8, the results vary from function to function. In case 3, an error occurs when f
is f4
but not in case 1 and case 2 or the case when f
is f2
where T
is not distributed using T extends any
.
Here is a table of whether a ts2322 error occurs in each cases:
f | Case 1 | Case 2 | Case 3 |
---|---|---|---|
f0 | 🛑 | 🛑 | 🛑 |
f1 | ⚪ | ⚪ | ⚪ |
f2 | ⚪ | ⚪ | ⚪ |
f3 | ⚪ | ⚪ | ⚪ |
f4 | ⚪ | ⚪ | 🛑 |
f5 | ⚪ | ⚪ | ⚪ |
f6 | 🛑 | 🛑 | 🛑 |
f7 | ⚪ | ⚪ | ⚪ |
For the latter half, f(n+8)
is simply fn
with Extract
expanded out, but I could hardly understand why the behavior changes:
f | Case 1 | Case 2 | Case 3 |
---|---|---|---|
f8 | 🛑 | 🛑 | 🛑 |
f9 | ⚪ | ⚪ | ⚪ |
fa | ⚪ | ⚪ | ⚪ |
fb | ⚪ | ⚪ | ⚪ |
fc | ⚪ | ⚪ | 🛑 |
fd | ⚪ | ⚪ | 🛑 |
fe | 🛑 | 🛑 | 🛑 |
ff | 🛑 | 🛑 | 🛑 |
(Tested in v4.9.0-dev.20221020 and 4.8.4)
Prior to 4.8, ALL the cases passed:
f | Case 1 | Case 2 | Case 3 |
---|---|---|---|
f0 | ⚪ | ⚪ | ⚪ |
f1 | ⚪ | ⚪ | ⚪ |
f2 | ⚪ | ⚪ | ⚪ |
f3 | ⚪ | ⚪ | ⚪ |
f4 | ⚪ | ⚪ | ⚪ |
f5 | ⚪ | ⚪ | ⚪ |
f6 | ⚪ | ⚪ | ⚪ |
f7 | ⚪ | ⚪ | ⚪ |
f8 | ⚪ | ⚪ | ⚪ |
f9 | ⚪ | ⚪ | ⚪ |
fa | ⚪ | ⚪ | ⚪ |
fb | ⚪ | ⚪ | ⚪ |
fc | ⚪ | ⚪ | ⚪ |
fd | ⚪ | ⚪ | ⚪ |
fe | ⚪ | ⚪ | ⚪ |
ff | ⚪ | ⚪ | ⚪ |
(Tested in 4.7.4 and 4.6.4)
(Note: some of the test functions above are for control (i.e. comparison) only.)
Expected behavior:
For each row, the results of case 1, case 2 and case 3 should be identical. (f4
, fc
, fd
)
For each column, the results of fn
and f(n+8)
should be identical. (f5
, fd
, f7
, ff
)
I understand that some of them must be desirable changes, so I am not expecting the results to be the same between 4.7 and 4.8, but the mismatched results due to the absent of generic constraint are really weird.