Hello i am trying to add correct type to object with nested values.
Here is code in sandbox: https://codesandbox.io/s/0tftsf
interface Product {
name: string,
id: number
productList?:ProductItem[]
}
interface ProductItem {
color: string,
size: number
}
type IValidation<T> = {
field: keyof T
nestedValidations?: IValidation<
Pick<
T,
{
[K in keyof T]-?: T[K] extends object ? K : never
}[keyof T]
>
>[] // THIS IS IMPORTANT FOR QUESTION!
validators?: (any | any | any)[]
}
export async function validateIt<T>(payload: T, validations: IValidation<T>[]): Promise<
Partial<{
[key in keyof T]: string[]
}>
> {
return Promise.resolve(payload);
}
const product: Product = {
id: 1,
name: 'playstation',
productList: [{
color: 'red',
size: 32
}
]
}
const test = validateIt<Product>(product, [
{
field: "productList",
validators: [],
nestedValidations: [
{
field: 'color',
validators: []
}
]
}
])
So getting type error and overall i am trying to find correct type for nestedValidations property, which should match interface Product
You can achieve this with in keyword in combination with keyof.
Basically you're going to "generate" all possible types for each key and typescript will find matching one
type IValidation<T> = T extends Array<infer R> ? IValidation<R> : T extends object ? {
[K in keyof T]: {
field: K
nestedValidations?: IValidation<T[K]>[]
validators?: (any | any | any)[]
}
}[keyof T] : never
Maybe I don't see the big picture but I think you want to achieve this:
interface Product {
name: string,
id: number
}
type ValueOf<T> = T[keyof T]; // not needed
type IValidation<T> = {
field: keyof T
nestedValidations?: IValidation<T>[] // THIS IS IMPORTANT FOR QUESTION!
validators?: (any | any | any)[]
}
export async function validateIt<T>(payload: T, validations: IValidation<T>[]): Promise<
Partial<{
[key in keyof T]: string[]
}>
> {
return Promise.resolve(payload);
}
const product: Product = {
id: 1,
name: 'playstation'
}
const test = validateIt<Product>(product, [
{
field: "id",
validators: [],
nestedValidations: [
{
field: "name",
validators: []
}
]
}
])
Play around here: Typescript Playground
Please note that I had to simplify your data structure since I don't know how 'IRequiredValidator' is defined.
So basically we switch from
nestedValidations?: IValidation<ValueOf<T>>[]
to
nestedValidations?: IValidation<T>[]
because you want to extract the keys of T and not the keys of ( keys of T) Since that would resolve to all the properties of the type of a value assigned to a property of T.