Reputation: 1984
Consider a nested object like below
class Person {
name: string = 'name';
address: {street: string, pincode: string} = {street: 'street', pincode: '44555'};
}
There is a utility function(undefinedAllLeadNodes) which undefines all leaf nodes. So passing a new Person() creates below
person.name = undefined
person.address.street = undefined;
person.address.pincode = undefined;
If i declare as below
export function undefineAllLeafProperties<
T extends object
>(obj : T) : {[key: string] : any} {
...undefine all leaf nodes here
}
It shows compilation error for person.address.street and it sounds fine for {[key: string] : any}
return type declaration.
But What can be the proper return type for the utility function(undefinedAllLeadNodes) so that i can access it like below without any errors
person.address.street = 'update only street';
Upvotes: 0
Views: 149
Reputation: 8340
You may define such a type like this:
type Undefine<T extends object> = {
[K in keyof T]: T[K] extends object ? Undefine<T[K]> : T[K] | undefined
}
Here we're using mapped types to iterate over all keys (using keyof operator) of the provided T
object and conditional type to check whether the value of T[K]
(using lookup type) is an object again. And when it is we recursivly iterate over the T[K]
keys. Otherwise (when T[K]
is not an object) we just change it's type to allow undefined
value along the main type of T[K]
.
Keep in mind that inside the undefineAllLeafProperties
function code you may have to type assert return values . Because typescript generally cannot infer the exact shape of the conditional type when it depends on unspecified generic type parameter.
Upvotes: 1