Search code examples
arraystypescriptextends

Typescript array checked as {[k:string]: any}


If i write the following type

type myType<T> = {
    [K in keyof T]?: T[K] extends ({[k:string]: any} | undefined) ? T[K] : 0
}

when T[K] is an array of any type, myType behaves as if T[K] extends ({[k:string]:any)|undefined) was true even if any[] is not a {[k:string]:any}. So when i try to use this type like this i get an error:

declare class obj {
    a?: string
    b?: any[] // <-- if this gets changed to a primitive there is no more error
    c?: {
        d: number
    }
}

const a: myType<obj> = {
    a: 0,
    b: 0, // <-- this gives an error
    c: {
        d: 1
    }
}

Playground Link


Solution

  • The problem is that Array<any> (number[], string[]...) actually extends the type Object.

    That is why any[] checks as {[k:string]: any}.

    To solve that, you should validate specifically for array, before validating for {[k:string]: any}.

    It would be something like:

    type myType<T> = {
      [K in keyof T]?: T[K] extends (Array<any> | undefined) ? 0 : (T[K] extends ({ [k: string]: any } | undefined) ? T[K] : 0)
    }
    

    | undefined can be removed if your array property is not optional.

    But as you can see you need to nest 2 conditionals.

    So instead of checking for a generic object { [k: string]: any }, I would recommend you create another type, so you could validate using your custom type.

    Otherwise, you might have more validation problems if you add other properties that are also objects.