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

Time:07-11

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}.

Playground Link

CodePudding user response:

Yes an array extends the type object, because an array is an object.

Here is a narrowed down example :

type Foo = [] extends {} ? 'array' : 'notArray';    
declare const foo:Foo; // 'array' 

A fix would to handle the array type seperatly :

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

declare class obj{
    a?: string
    b?: any[] // OK
    c?: {
        d: number
    }
}

Playground

CodePudding user response:

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.

  • Related