Description
TypeScript Version: 4.1.2
Search Terms:
Code
const aggregatedResults: (number[] | null | 'loading')[] = [[1, 2], null, [3, 4], 'loading', [5, 6]]
const onlyTheArrays = aggregatedResults.filter<number[]>(Array.isArray) // number[][]
making it easy to chain with more calls, e.g. .flat()
.
number[]
needed to be passed so the end result was not any[]
, but it was type-safe, passing e.g. boolean[]
would give an error.
Expected behavior:
Array.isArray
as a native type guard function should be composable with type-guard accepting functions like array.filter()
. Those functions need to be able to pluck the narrowed type out of the signature.
The above code worked in TS 4.0.
Actual behavior:
In TS 4.2 it seems like the signature of Array.isArray
was changed and now has a conditional return type, which seems to make it impossible to pass it to a type-guard accepting function like array.filter()
. The above code now gives an error (Playground):
Argument of type '<T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]' is not assignable to parameter of type '(value: number[] | "loading" | null, index: number, array: (number[] | "loading" | null)[]) => value is number[]'.
Type predicate 'arg is any[] | readonly any[]' is not assignable to 'value is number[]'.
Type 'any[] | readonly any[]' is not assignable to type 'number[]'.
The type 'readonly any[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
array.filter()
can't pluck the narrowed type out of the signature anymore because of the complex conditional type.
Related Issues: I think this was broken by #39258