My root problem is following, I need to detect that a type is Array<any>
(not any other Array type).
I can detect this with 2 combined conditions : T extends Array<any>
and Array<any> extends
How could I write a conditional type without having to resort to a double ternary like following:
type foo<T> = T extends Array<any> ? Array<any> extends T ? T : 'not any array' : 'not any array';
Here is a method that works using only 1 conditional type, borrowing the trick from this answer:
type foo<T> = [1[] & T, any[]] extends [0[], T] ? T : "not any array";
There's two checks going on here: one two check for any[]
, and the other two disallow never[]
. To check for any[]
, we're using the same principle as the linked answer: any
allows us to do some crazy things, like assigning 1[]
to 0[]
. This however, also allows never[]
to slip by.
To address never[]
, we use another check. Because never
is the bottom type, nothing is assignable to it,. This means that checking if any[]
is assignable to T
is all we need.
Example tests:
type T01 = foo<any[]>
// ^? any[]
type T02 = foo<never[]>
// ^? "not any array"
type T03 = foo<number[]>
// ^? "not any array"
type T04 = foo<{ bar: any }>
// ^? "not any array"
type T05 = foo<{ 1: any }>;
// ^? "not any array"