Is your feature request related to a real problem or use-case?
Add a deep recursive Optional type and its inverse a deep recursive Required type both of which should work with providing path definitions into a deeply nested type and only switch those properties to optional or required that are defined as keys.
This feature is particular helpful if you have deeply nested types in a "workflow" like environment where as your object moves across the system more and more properties become mandatory at each workflow step.
Describe a solution including usage in code example
I have implemented the whole thing for the DeepRecursiveOptional already
The reverse DeepRecursiveRequired should be relatively easy thou.
//need to use Pick2 instead of Pick because Pick only works with keyof T
type Pick2<T, Path extends string> = {
[K in keyof T]: K extends Path
? T[K]
: never;
};
//Helper to remove never properties which will be generated by Pick2
//as it works with strings and not the keyof operator
type RemoveNeverProperties<T> = {
[K in keyof T as T[K] extends never ? never : K]: T[K];
};
//we first omit the properties that are to be optional & then we pick those
//remove any never props and make the result Partial
//at last we join the remainder with the newly partial properties
type Optional2<T extends object, K extends string> =
Omit<T, K> & Partial<RemoveNeverProperties<Pick2<T, K>>>;
//Helper to check if a property needs to be handled recursevely
//and Helper that cuts the prefix for the next nesting level
type ShiftPath<Key extends PropertyKey, Path extends PropertyKey> =
Path extends `${Extract<Key, string>}.${infer Rest}` ? Rest : never;
//Putting everything together
export type DeepRecursiveOptional<T, Path extends string> =
//make the defined props optional if they match on this nesting level
Optional2<{
//iterate thru each prop
[K in keyof T]:
//check if a "path" points into the next nesting level
ShiftPath<K, Path> extends never
//if not return the property without any change
? T[K]
//else recursively apply optionality
: DeepRecursiveOptional<T[K], ShiftPath<K, Path>>;
}, Path>;
type A = {
prop_a: string
prop_b: string
prop_c: {
prop_d: boolean
prop_e: number
prop_f: {
prop_g: Date
prop_h: string
}
}
}
type B = DeepRecursiveOptional<A, "prop_a" | "prop_c.prop_d" | "prop_c.prop_f.prop_g">
const b: B = {
//prop_a: "test",
prop_b: "test",
prop_c: {
//prop_d: true,
prop_e: 1,
prop_f: {
//prop_g: new Date(),
prop_h: "test"
}
}
}
Who does this impact? Who is this for?
This is for typescript users
Describe alternatives you've considered (optional)
Having in mind a workflow like system with deeply neseted types ... the only way would be to always to rebuild the whole deeply nested type for each Workflow step. This introduces the possibility for eventually renaming a property and you loose the single source of truth in your code base.
Additional context (optional)
This solution is not as typesafe as one would wish for as I am operating with strings that define paths instead of using the keyof operator. Otoh it seems to me a rather insignificant drawback. If one defines a path into a (nested) property that does not exist due to a typo (let say "footbar" vs "foobar" ´) then the only thing that happens is that at the usage site the property will be still required instead of optional and the compiler will tell that
Is your feature request related to a real problem or use-case?
Add a deep recursive Optional type and its inverse a deep recursive Required type both of which should work with providing path definitions into a deeply nested type and only switch those properties to optional or required that are defined as keys.
This feature is particular helpful if you have deeply nested types in a "workflow" like environment where as your object moves across the system more and more properties become mandatory at each workflow step.
Describe a solution including usage in code example
I have implemented the whole thing for the
DeepRecursiveOptional
already The reverseDeepRecursiveRequired
should be relatively easy thou.Who does this impact? Who is this for?
This is for typescript users
Describe alternatives you've considered (optional)
Having in mind a workflow like system with deeply neseted types ... the only way would be to always to rebuild the whole deeply nested type for each Workflow step. This introduces the possibility for eventually renaming a property and you loose the single source of truth in your code base.
Additional context (optional)
This solution is not as typesafe as one would wish for as I am operating with strings that define paths instead of using the keyof operator. Otoh it seems to me a rather insignificant drawback. If one defines a path into a (nested) property that does not exist due to a typo (let say "footbar" vs "foobar" ´) then the only thing that happens is that at the usage site the property will be still required instead of optional and the compiler will tell that