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.
