typescripttypescript-genericstypescript-conditional-types

Better way to check for Array<any> type


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';

Solution

  • 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"
    

    Playground