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