DEV Community

Cover image for How to dynamically assign properties to an object in TypeScript
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

How to dynamically assign properties to an object in TypeScript

Written by Ohans Emmanuel✏️

Introduction

Consider the following example:

const organization = {}
organization.name = "Logrocket"                                                                                 
Enter fullscreen mode Exit fullscreen mode

This seemingly harmless piece of code throws a TypeScript error on dynamically assigning name to the organization object. An error is thrown when dynamically assigning a property to an object

See this example in the TypeScript Playground.

The source of confusion, which is perhaps rightly justified if you’re a TypeScript beginner, is: how could something that seems so simple be such a problem in TypeScript?

The TL;DR of it all is that, if you cannot define the variable type at declaration time, you can use the Record utility type or an object index signature to solve this. But in this post, we’ll go through the problem itself and work toward a solution that should work in most cases.

Jump ahead:

Understanding the problem with dynamically assigning properties to objects

Generally speaking, TypeScript determines the type of a variable when it is declared, and this determined type doesn’t change, i.e., it stays the same all through your application.

There are exceptions to this rule, such as when considering type narrowing or working with the any type, but this is a general rule to remember otherwise.

In the earlier example, the organization object is declared as follows:

const organization = {}
Enter fullscreen mode Exit fullscreen mode

There is no explicit type assigned to the organization variable, so TypeScript infers a type of organization based on the declaration to be {}, i.e., the literal empty object.

For example, if you add a type alias, you can explore the type of organization:

type Org = typeof organization
Enter fullscreen mode Exit fullscreen mode

Exploring the literal object type

See this in the TypeScript Playground.

When you then try to reference the name prop on this empty object literal:

organization.name = ...
Enter fullscreen mode Exit fullscreen mode

TypeScript yells.

Property 'name' does not exist on type ‘ {}

When you understand the issue, the error does seem appropriate.

Let’s fix this.

Resolving the problem

There are numerous ways you can resolve the TypeScript error here. Let’s consider these:

Solution 1: Explicitly type the object at declaration time

This is the easiest solution to reason through. At the time you declare the object, go ahead and type it. Furthermore, assign it all the relevant values.

type Org = {
    name: string
}

const organization: Org = {
    name: "Logrocket"
}
Enter fullscreen mode Exit fullscreen mode

See this in the TypeScript Playground.

This eliminates any surprises. You’re clearly stating what this object type is and rightly declaring all relevant properties when you create the object.

However, this is not always feasible if the object properties must be added dynamically, which is why we’re all here.

Solution 2: Use an object index signature

Occasionally, the properties of the object truly need to be added at a time after they’ve been declared. In this case, you can use the object index signature, as follows:

type Org = {[key: string] : string}
const organization: Org = {}
organization.name = "Logrocket"
Enter fullscreen mode Exit fullscreen mode

See this in the TypeScript Playground.

At the time the organization variable is declared, you can go ahead and explicitly type it to the following {[key: string] : string}.

To explain the syntax further, you might be used to object types having fixed property types:

type obj = {
  name: string
}
Enter fullscreen mode Exit fullscreen mode

However, you can also substitute name for a “variable type”.

For example, if you want to define any string property on obj:

type obj = {
 [key: string]: string
}
Enter fullscreen mode Exit fullscreen mode

Note that the syntax is similar to how you’d use a variable object property in standard JavaScript:

const variable = "name" 
const obj = {
   [variable]: "Freecodecamp"
}
Enter fullscreen mode Exit fullscreen mode

The TypeScript equivalent is called an object index signature. Moreover, note that you could type key with other primitives:

// number 
type Org = {[key: number] : string}

// string 
type Org = {[key: string] : string}

//boolean
type Org = {[key: boolean] : string}
Enter fullscreen mode Exit fullscreen mode

Solution 3: Use the Record utility type

The Record utility type allows you to constrict an object type whose properties are Keys and property values are Type. It has the following signature: Record<Keys, Type>.

In our example, Keys represents string and Type, string as well. The solution here is quite concise as shown below:

type Org = Record<string, string>

const organization: Org = {}

organization.name = "Logrocket"
Enter fullscreen mode Exit fullscreen mode

Instead of using a type alias, you can also inline the type:

const organization: Record<string, string> = {}
Enter fullscreen mode Exit fullscreen mode

Using the Record utility type

See this in the TypeScript Playground.

Conclusion

Apart from primitives, the most common types you’ll have to deal with are likely object types.

In cases where you need to build an object dynamically, take advantage of the Record utility type or use the object index signature to define the allowed properties on the object.

If you’d like to read more on this subject, feel free to check out my cheatsheet on the seven most-asked TypeScript questions on Stack Overflow, or tweet me any questions. Cheers!


LogRocket proactively surfaces and diagnoses the most important issues in your TypeScript apps

Diagnose Issues In Your TypeScript Apps

Thousands of engineering and product teams use LogRocket to reduce the time it takes to understand the root cause of technical and usability issues in their TypeScript apps. With LogRocket, you'll spend less time on back-and-forth conversations with customers and remove the endless troubleshooting process. LogRocket allows you to spend more time building new things and less time fixing bugs.

Proactively fix your TypeScript apps — try LogRocket today.

Top comments (0)