How to Get an Object Value by Dynamic Keys in TypeScript

Avatar

By squashlabs, Last Updated: October 13, 2023

How to Get an Object Value by Dynamic Keys in TypeScript

Table of Contents

Imagine a scenario where we have an object representing a user profile, and we want to retrieve the value of a specific property based on user input. Without the ability to access object properties dynamically, we would need to use multiple if statements or switch cases to handle each possible property. This approach would quickly become cumbersome and difficult to maintain as the number of properties increases.

Example 1: Accessing Object Properties Dynamically

Let’s consider a simple example where we have an object representing a user profile:

const userProfile = {
name: "John Doe",
age: 30,
email: "john.doe@example.com",
};

const propertyName = "age";
const propertyValue = userProfile[propertyName];

console.log(propertyValue); // Output: 30

In this example, we have an object userProfile with properties like name, age, and email. We want to retrieve the value of a specific property based on the value of the propertyName variable. By using the bracket notation ([]), we can dynamically access the object property and assign it to the propertyValue variable.

Related Article: Using ESLint & eslint-config-standard-with-typescript

Example 2: Dynamic Access to Nested Object Properties

Dynamic access to object properties becomes even more useful when dealing with nested objects. Let’s consider an example where we have an object representing a user’s address:

const user = {
name: "John Doe",
address: {
street: "123 Main St",
city: "New York",
},
};

const propertyPath = "address.city";
const propertyValue = propertyPath.split('.').reduce((obj, key) => obj?.[key], user);

console.log(propertyValue); // Output: New York

In this example, we have an object user with a nested object representing the user’s address. We want to retrieve the value of the city property dynamically, even though it is nested within the address property. By splitting the propertyPath string and using reduce with the bracket notation, we can dynamically access the nested property and retrieve its value.

Example 1: Dynamic Key Access with Type Safety in TypeScript

Let’s consider an example where we have an object representing a user profile in TypeScript:

interface UserProfile {
name: string;
age: number;
email: string;
}

const userProfile: UserProfile = {
name: "John Doe",
age: 30,
email: "john.doe@example.com",
};

const propertyName: keyof UserProfile = "age";
const propertyValue = userProfile[propertyName];

console.log(propertyValue); // Output: 30

In this example, we define an interface UserProfile to specify the structure and types of the object properties. By using the keyof operator, we can assign the propertyName variable to be one of the keys of the UserProfile interface, ensuring that we only access valid properties. This provides type safety and helps catch potential errors during development.

Example 2: Dynamic Key Access with Optional Properties

TypeScript also allows us to work with objects that have optional properties. Let’s consider an example where we have an object representing a user profile with optional properties:

interface UserProfile {
name: string;
age?: number;
email?: string;
}

const userProfile: UserProfile = {
name: "John Doe",
};

const propertyName: keyof UserProfile = "age";
const propertyValue = userProfile[propertyName];

console.log(propertyValue); // Output: undefined

In this example, we define the age and email properties in the UserProfile interface as optional by using the ? modifier. This allows us to work with objects that may not have all properties defined. When accessing optional properties dynamically, TypeScript correctly infers the type of the property value as number | undefined, providing better type safety.

Related Article: How to Work with Anonymous Classes in TypeScript

Common Use Cases for Accessing Object Properties with Dynamic Keys

Accessing object properties dynamically is a useful feature that finds applications in various scenarios. Here are some common use cases where dynamic key access is useful:

1. Form Handling

When working with forms, we often need to extract values based on the input field name or ID. Dynamic key access allows us to retrieve these values without hardcoding every possible field name. This is particularly useful when dealing with dynamic forms or forms with a large number of fields.

const formData = {
name: "John Doe",
age: 30,
email: "john.doe@example.com",
};

function getFormFieldValue(fieldName: string): string | undefined {
return formData[fieldName];
}

console.log(getFormFieldValue("name")); // Output: John Doe
console.log(getFormFieldValue("email")); // Output: john.doe@example.com

In this example, the getFormFieldValue function accepts a fieldName parameter and retrieves the corresponding value from the formData object using dynamic key access. This allows us to extract form values based on user input or other runtime conditions.

2. API Responses

When consuming APIs, the response data often contains nested objects or unknown properties. Dynamic key access enables us to extract the required data without explicitly knowing the structure in advance. This makes our code more resilient to API changes and allows for more flexible data processing.

const apiResponse = {
data: {
id: 123,
user: {
name: "John Doe",
email: "john.doe@example.com",
},
},
};

function getApiResponseValue(propertyName: string): any {
const propertyPath = propertyName.split('.');
return propertyPath.reduce((obj, key) => obj?.[key], apiResponse);
}

console.log(getApiResponseValue("data.user.name")); // Output: John Doe
console.log(getApiResponseValue("data.user.email")); // Output: john.doe@example.com

In this example, the getApiResponseValue function accepts a propertyName parameter representing the desired property in the API response. By splitting the propertyName and using dynamic key access with reduce, we can retrieve the corresponding value from the apiResponse object, even if it is nested within other properties.

Related Article: Building a Rules Engine with TypeScript

Different Approaches for Accessing Object Properties Dynamically

There are multiple approaches to access object properties dynamically in TypeScript. Let’s explore some of the common methods:

1. Using Object Bracket Notation

One of the most common approaches to access object properties dynamically is by using the bracket notation ([]). This notation allows us to access object properties using a variable or dynamic key.

const obj = {
key: "value",
};

const dynamicKey = "key";
const value = obj[dynamicKey];

console.log(value); // Output: value

In this example, we have an object obj with a property named key. We use a variable dynamicKey to hold the property name, and then access the property value using the bracket notation ([]).

2. Using Object Dot Notation

Another approach to access object properties dynamically is by using the dot notation (.). While the dot notation is commonly used to access object properties directly, it can also be used dynamically with the help of the eval function or object destructuring.

const obj = {
key: "value",
};

const dynamicKey = "key";
const value = eval(`obj.${dynamicKey}`);

console.log(value); // Output: value

In this example, we have an object obj with a property named key. We use the eval function to evaluate the dynamic key expression obj.dynamicKey, which allows us to access the property value dynamically.

Related Article: How to Implement ETL Processes with TypeScript

3. Using Object Methods

Some objects in TypeScript provide methods that allow for dynamic key access. For example, the Map object provides the get method, which allows us to retrieve a value based on a key.

const map = new Map<string, string>();
map.set("key", "value");

const dynamicKey = "key";
const value = map.get(dynamicKey);

console.log(value); // Output: value

In this example, we create a Map object and set a key-value pair. We then use a variable dynamicKey to hold the key and retrieve the corresponding value using the get method.

4. Using the in Operator

The in operator in TypeScript allows us to check if a specific property exists in an object. This can be useful when accessing object properties dynamically, as we can first check if the property exists before attempting to access it.

const obj = {
key: "value",
};

const dynamicKey = "key";
const keyExists = dynamicKey in obj;

console.log(keyExists); // Output: true

In this example, we have an object obj with a property named key. We use the in operator to check if the dynamic key dynamicKey exists in the object. The result is a boolean value indicating whether the property exists.

Using Object Bracket Notation to Access Object Properties with Dynamic Keys

One of the most common and straightforward approaches to access object properties dynamically in TypeScript is by using the bracket notation ([]). This notation allows us to access object properties using a variable or dynamic key.

Related Article: TypeScript ETL (Extract, Transform, Load) Tutorial

Example 1: Accessing Object Properties with Dynamic Keys

Let’s consider a simple example where we have an object representing a user profile:

const userProfile = {
name: "John Doe",
age: 30,
email: "john.doe@example.com",
};

const propertyName = "age";
const propertyValue = userProfile[propertyName];

console.log(propertyValue); // Output: 30

In this example, we have an object userProfile with properties like name, age, and email. We want to retrieve the value of a specific property based on the value of the propertyName variable. By using the bracket notation ([]), we can dynamically access the object property and assign it to the propertyValue variable.

Example 2: Dynamic Access to Nested Object Properties

Dynamic access to object properties becomes even more useful when dealing with nested objects. Let’s consider an example where we have an object representing a user’s address:

const user = {
name: "John Doe",
address: {
street: "123 Main St",
city: "New York",
},
};

const propertyPath = "address.city";
const propertyValue = propertyPath.split('.').reduce((obj, key) => obj?.[key], user);

console.log(propertyValue); // Output: New York

In this example, we have an object user with a nested object representing the user’s address. We want to retrieve the value of the city property dynamically, even though it is nested within the address property. By splitting the propertyPath string and using reduce with the bracket notation, we can dynamically access the nested property and retrieve its value.

Using Object Dot Notation to Access Object Properties with Dynamic Keys

Another approach to access object properties dynamically in TypeScript is by using the dot notation (.). While the dot notation is commonly used to access object properties directly, it can also be used dynamically with the help of the eval function or object destructuring.

Related Article: Tutorial on Circuit Breaker Pattern in TypeScript

Example 1: Accessing Object Properties with Dynamic Keys using eval

Using the eval function, we can evaluate a dynamic key expression and access the corresponding property value.

const obj = {
key: "value",
};

const dynamicKey = "key";
const value = eval(`obj.${dynamicKey}`);

console.log(value); // Output: value

In this example, we have an object obj with a property named key. We use the eval function to evaluate the dynamic key expression obj.dynamicKey, which allows us to access the property value dynamically.

Example 2: Accessing Object Properties with Dynamic Keys using Object Destructuring

Object destructuring is another way to access object properties dynamically using the dot notation.

const obj = {
key: "value",
};

const dynamicKey = "key";
const { [dynamicKey]: value } = obj;

console.log(value); // Output: value

In this example, we have an object obj with a property named key. We use object destructuring and the bracket notation to dynamically assign the property value to the value variable.

Using Object Methods to Access Object Properties with Dynamic Keys

Some objects in TypeScript provide methods that allow for dynamic key access. One such example is the Map object, which provides the get method to retrieve a value based on a key.

Example 1: Accessing Object Properties with Dynamic Keys using the get Method

Let’s consider an example where we have a Map object representing key-value pairs:

const map = new Map<string, string>();
map.set("key", "value");

const dynamicKey = "key";
const value = map.get(dynamicKey);

console.log(value); // Output: value

In this example, we create a Map object and use the set method to add a key-value pair. We then use the get method to retrieve the value based on the dynamic key dynamicKey.

Example 2: Accessing Object Properties with Dynamic Keys using Custom Methods

In addition to the built-in object methods, we can also create custom methods to access object properties dynamically. Let’s consider an example where we have a custom class with a method to retrieve a property value based on a dynamic key.

class User {
private data: Record<string, string>;

constructor() {
this.data = {
name: "John Doe",
email: "john.doe@example.com",
};
}

getProperty(key: string): string | undefined {
return this.data[key];
}
}

const user = new User();
const propertyKey = "email";
const propertyValue = user.getProperty(propertyKey);

console.log(propertyValue); // Output: john.doe@example.com

In this example, we define a User class with a private data property that holds key-value pairs. The class has a getProperty method that accepts a dynamic key and retrieves the corresponding property value from the data object.

Using the in Operator to Check if an Object Property Exists

The in operator in TypeScript allows us to check if a specific property exists in an object. This can be useful when accessing object properties dynamically, as we can first check if the property exists before attempting to access it.

Example 1: Checking if an Object Property Exists using the in Operator

Let’s consider an example where we have an object obj with a property named key. We use the in operator to check if the dynamic key dynamicKey exists in the object.

const obj = {
key: "value",
};

const dynamicKey = "key";
const keyExists = dynamicKey in obj;

console.log(keyExists); // Output: true

In this example, we have an object obj with a property named key. We use the in operator to check if the dynamic key dynamicKey exists in the object. The result is a boolean value indicating whether the property exists.

Example 2: Checking if a Nested Object Property Exists

The in operator can also be used to check if a nested property exists in an object. Let’s consider an example where we have an object representing a user with a nested object representing the user’s address.

const user = {
name: "John Doe",
address: {
city: "New York",
},
};

const dynamicKey = "address.city";
const propertyPath = dynamicKey.split('.');
const propertyExists = propertyPath.reduce((obj, key) => obj && key in obj ? obj[key] : undefined, user);

console.log(propertyExists); // Output: true

In this example, we have an object user with a nested object representing the user’s address. We use the in operator in conjunction with reduce to check if the dynamic key dynamicKey exists in the object. The result is a boolean value indicating whether the property exists.

Handling Non-existent Object Properties When Accessing Dynamically

When accessing object properties dynamically, it is important to handle cases where the property may not exist. By implementing proper error handling or fallback mechanisms, we can ensure that our code behaves as expected even when encountering non-existent properties.

Example 1: Handling Non-existent Object Properties with Conditional Statements

A common approach to handling non-existent object properties is by using conditional statements such as if or the ternary operator (?:). This allows us to check if the property exists before attempting to access it and provide a default value or fallback behavior.

const obj = {
key: "value",
};

const dynamicKey = "nonExistentKey";
const value = obj.hasOwnProperty(dynamicKey) ? obj[dynamicKey] : "default";

console.log(value); // Output: default

In this example, we have an object obj with a property named key. We attempt to access the dynamic key nonExistentKey, which does not exist in the object. By using the hasOwnProperty method to check if the property exists, we can provide a default value of “default” if the property is non-existent.

Example 2: Handling Non-existent Object Properties with Optional Chaining

TypeScript 3.7 introduced the optional chaining operator (?.), which provides a concise way to handle non-existent object properties. By using optional chaining, we can access nested properties without causing errors if any intermediate property is non-existent.

const user = {
name: "John Doe",
};

const propertyPath = "address.city";
const propertyValue = propertyPath.split('.').reduce((obj, key) => obj?.[key], user);

console.log(propertyValue); // Output: undefined

In this example, we have an object user with a property named name. We attempt to access the nested property address.city, even though the address property does not exist. By using optional chaining with the bracket notation ([]), we can gracefully handle the non-existent property and assign undefined to the propertyValue variable.

Best Practices for Working with Dynamic Keys and Object Properties

When working with dynamic keys and object properties in TypeScript, it is important to follow some best practices to ensure code readability, maintainability, and performance. Here are some recommended best practices:

1. Use Meaningful Variable Names

When working with dynamic keys, choose variable names that accurately describe their purpose or the property they represent. This improves code readability and makes it easier for other developers to understand the code.

2. Validate Dynamic Keys

Before accessing object properties dynamically, validate the dynamic keys to ensure they are valid and exist in the object. This helps prevent potential errors and allows for proper error handling or fallback mechanisms.

3. Provide Default Values or Fallbacks

When accessing object properties dynamically, consider providing default values or fallbacks in case the property is non-existent. This ensures that the code behaves as expected even in scenarios where the property may not exist.

4. Use Type Safety

In TypeScript, leverage type safety to ensure that dynamic key access is valid and aligns with the defined types of the object and its properties. This helps catch potential errors during development and provides better code completion and IDE support.

5. Avoid Excessive Nesting

Avoid excessive nesting of objects when possible, as it can make dynamic key access more complex and error-prone. Consider flattening object structures or using alternative data structures like maps or arrays when appropriate.

6. Document Dynamic Key Usage

When using dynamic key access, document the purpose and usage of the dynamic keys to provide clarity to other developers. This helps improve code maintainability and reduces the chances of introducing errors during future modifications.

External Sources

TypeScript Handbook: Indexable Types
MDN Web Docs: Bracket notation