31
loading...
This website collects cookies to deliver better user experience
const person = {
name: "John",
age: 30,
dog:{
name: "Rex",
}
}
function get<ObjectType>(object: ObjectType, path: string){
const keys = path.split('.');
let result = object;
for (const key of keys) {
result = result[key];
}
return result;
}
get(person, "dog.name") // Rex
keyof
operator will serve just fine!const person = {
name: "John",
age: 30,
job: "Programmer"
}
function get<ObjectType>(object: ObjectType,
path: keyof ObjectType & string){
...
}
"name"
, "age"
or "job"
as the second argument.keyof
isn't nearly enough as you may have realized by now.const objectKeys = [];
const person = {
name: 'pfigueiredo',
age: 30,
dog: {
owner: {
name: 'pfigueiredo'
}
}
};
function getObjectKeys(obj, previousPath = '') {
// Step 1- Go through all the keys of the object
Object.keys(obj).forEach((key) => {
// Get the current path and concat the previous path if necessary
const currentPath = previousPath ? `${previousPath}.${key}` : key;
// Step 2- If the value is a string, then add it to the keys array
if (typeof obj[key] !== 'object') {
objectKeys.push(currentPath);
} else {
objectKeys.push(currentPath);
// Step 3- If the value is an object, then recursively call the function
getObjectKeys(obj[key], currentPath);
}
});
}
getObjectKeys(person); // [ 'name', 'age', 'dog', 'dog.owner', 'dog.owner.name' ]
generic type
that will give us all the keys of an object as literal types.type NestedKeyOf = {};
type NestedKeyOf<ObjectType> = {};
// using
type ObjectKeys = NestedKeyOf<Person>;
extends
keyword, in order to only accept object types - any type that follows the "key-value" pair data type.type NestedKeyOf<ObjectType extends object> = {};
// Create an object type from `ObjectType`, where the keys
// represent the keys of the `ObjectType` and the values
// represent the values of the `ObjectType`
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType]: ObjectType[Key]};
// Take a `Type`, check if it "extends" `AnotherType`
// and return a type based on that
type Example = Dog extends Animal ? number : string;
// If the value is NOT of type `object` then
// set it as the generated object's value type
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType]: ObjectType[Key] extends object
? "" /*TODO*/
: Key
};
// But we want what's under the object's values,
// so we need to access it
type NestedKeyOf<ObjectType extends object> =
{...}[keyof ObjectType];
type Person = {
name: 'pfigueiredo',
age: 30,
dog: {
owner: {
name: 'pfigueiredo'
}
}
};
NestedKeyOf<Person>; // "name" | "age" | ""
dog.owner
and dog.owner.name
.// 1 - If it's an object, call the type again
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType]: ObjectType[Key] extends object
? NestedKeyOf<ObjectType[Key]>
: Key
}[keyof ObjectType];
// 2 - Concat the previous key to the path
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType]: ObjectType[Key] extends object
? `${Key}.${NestedKeyOf<ObjectType[Key]>}`
: Key
}[keyof ObjectType];
// 3 - Add the object's key
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType]: ObjectType[Key] extends object
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`
: Key
}[keyof ObjectType];
NestedKeyOf
utility type should already be capable of extracting all the possible property paths of an object with any given depth, but TypeScript will probably still be yelling at you for using non-strings/numbers inside the literals, let's fix that!&
operator. // add `& (string | number)` to the keyof ObjectType
type NestedKeyOf<ObjectType extends object> =
{[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`
: `${Key}`
}[keyof ObjectType & (string | number)];
sortBy
function, we are able to safely select one of the object's properties and make sure we don't do any typo and keep in sync with the object's structure and what we are passing at all times 🤯