Advisory boards aren’t only for executives. Join the LogRocket Content Advisory Board today →
- Product Management
- Solve User-Reported Issues
- Find Issues Faster
- Optimize Conversion and Adoption
- Start Monitoring for Free
How to dynamically assign properties to an object in TypeScript
Editor’s note: This article was updated by Yan Sun on 1 October 2024 to cover recent improvements to index access handling in TypeScript 5.5.
Dynamic property assignment is the ability to add properties to an object as needed, rather than defining them upfront. This is useful when properties are conditionally assigned in different parts of the code.
In TypeScript, we can dynamically assign properties to an object using the following methods:
- Explicitly declaring object type : Explicitly typing objects at declaration time is the simplest approach, but it might not be feasible when properties need to be added dynamically
- Using object index signature : This allows us to define the type of keys and value, and assign dynamic properties in an object
- Using the Record utility type : With the Record type, we can create an object type with specified keys and values, as in Record<string, string> , where both the keys and values are of type string
- Using the Map data type : Using a Map object allows dynamic property assignment, although it lacks strong typing
- Using optional object property : By declaring an optional property during object initialization like {name?: string} , we can enable dynamic assignment
- Leveraging type assertions : Type assertions in TypeScript override inferred types, allowing dynamic property assignment without type enforcement
- Using the Partial utility type : The Partial utility type makes all properties of a type optional, allowing us to initialize an object with any combination of the properties
In this article, we will explore how to benefit from both JavaScript’s dynamism and TypeScript’s type safety, particularly when working with dynamic property assignments.
Consider the following example code:
This seemingly harmless piece of code throws a TypeScript error when dynamically assigning the name property to the organization object:
See this example in the TypeScript Playground .
The source of confusion, perhaps rightly justified if you’re a TypeScript beginner, is: how could something so simple be such a problem in TypeScript?
In short, if we can’t define the variable type at declaration time, we can use the Record utility type or an object index signature to solve this. But in this article, we’ll work through the problem itself and toward a solution that should work in most cases.
The problem with dynamically assigning properties to objects
Generally speaking, TypeScript determines the type of a variable when it is declared. This determined type stays the same throughout our application. There are exceptions to this rule, such as when considering type narrowing or working with the any type, but otherwise, this is a general rule to remember.
In the earlier example, the organization object is declared as follows:
No explicit type is assigned to this variable, so TypeScript infers a type of organization based on the declaration to be {} , i.e., the literal empty object.
If we add a type alias, we can explore the type of organization :
See this in the TypeScript Playground .
Then, if we try to reference the name prop on this empty object literal:
We will receive the following error:
There are many ways to solve the TypeScript error here. Let’s consider the following:
Solution 1: Explicitly declare the object type
This is the easiest solution to reason through. At the time we declare the object, go ahead and type it, and assign all the relevant values:
This approach eliminates any surprises. By clearly stating what this object type is and declaring all relevant properties upfront, we ensure clarity and avoid unexpected behavior.
However, this is not always feasible if the object properties must be added dynamically, which is why we’re here.
Solution 2: Use object index signature
Occasionally, the properties of the object need to be added at a time after they’ve been declared. In this case, we can use the object index signature as follows:
In the example, we explicitly type the organization variable to the following: {[key: string] : string} , which allows this type to have properties with any string key and string value.
We might be used to object types having fixed property types:
However, we can also substitute the name property for a “variable type.” For example, if we want to define any string property on obj :
Note that the syntax is similar to how we’d use a variable object property in standard JavaScript:
The TypeScript equivalent is called an object index signature.
Moreover, note that we could type key with other primitive types such as string , number , symbol , or literal types:
Nested index signature
We can use nested indexed signatures to represent complex data structures. It allows us to handle dynamic properties in a nested structure:
Here, the Org type represents a data structure with properties with string keys, and each property can also be an object with string keys and string values.
We can go one step further to define a type with deeply nested index signatures. The example below demonstrates the ability to assign dynamic properties to deeply nested objects:
See the TypeScript playground.
Index signature with mapping types
Sometimes, a limited set of properties is known upfront. We can use the index signature and mapping types to create objects with properties named after union types:
The above example defines a type Org with keys based on a union of department names. The OrgHierachy type uses the Partial utility type to make all the properties optional, giving us the flexibility to not assign all the departments.
Over 200k developers use LogRocket to create better digital experiences
Solution 3: Use the Record utility type
The Record utility type allows us to construct 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 the string type. The solution here is shown below:
Instead of using a type alias, we can also use an inline type:
Solution 4: Use the Map data type
A Map object is a fundamentally different data structure from an object , but for completeness, we could eliminate this problem using Map .
Consider the starting example rewritten to use a Map object:
With Map objects, we’ll have no errors when dynamically assigning properties to the object:
This seems like a great solution initially, but the caveat is that the Map object is weakly typed. We can access a nonexisting property and get no warnings at all:
See the TypeScript Playground .
Unlike the standard object, an initialized Map has the key and value types as any — i.e., new () => Map<any, any> . Consequently, the return type of the s variable will be any :
When using Map , at the very least, I recommend passing some type of information upon creation. For example:
The variable s will still be undefined, but we won’t be surprised by its code usage. We’ll now receive the appropriate type for it:
If we truly don’t know what the keys of the Map will be, we can go ahead and represent this at the type level:
Similarly, if we’re not sure what the keys or values are, be safe by representing this at the type level:
Solution 5: Use the optional object property
While not always feasible, if we know the specific property to be dynamically assigned, we can declare it as an optional property during object initialization as shown below:
If you don’t like the idea of using optional properties, you can be more explicit with the typing:
Solution 6: Leveraging type assertions
TypeScript type assertion is a mechanism that tells the compiler the variable’s type and overrides what it infers from the declaration or assignment. With this, we are telling the compiler to trust our understanding of the type because there will be no type verification.
We can perform a type assertion by either using the <> brackets or the as keyword. This is particularly helpful with the dynamic property assignment because it allows the properties we want for our object to be dynamically set. After all, TypeScript won’t enforce them.
Let’s take a look at applying type assertions to our example:
Note that, with type assertions, the compiler trusts that we will enforce the type we have asserted. This means if we don’t, for example, set a value for organization.name , it will throw an error at runtime that we will have to handle ourselves.
Solution 7: Use the Partial utility type
TypeScript provides several utility types that can be used to manipulate types. These utility types include Partial , Omit , Required , and Pick .
We will focus specifically on the Partial utility type for dynamic property assignments. The Partial utility type takes a defined type and makes all of its properties optional. Thus, we can initialize our object with any combination of its properties, from none to all, as each one is optional:
In our example, we defined our organization object as the type partial Org , which means we can choose not to set a phoneNumber property:
Comparing approaches for dynamic property assignment in TypeScript
In this article, we explored the different options for setting properties dynamically in TypeScript. These options can be grouped by their similarities.
Index/Key signatures
This group of options allows us to define the type of keys allowed without limiting what possible keys can exist. The options in this group include:
- Using an object index signature
- Using the Record utility type
- Using the Map data type (with key/value typing)
With these approaches, we can define the string type for the object key and decide what types to support as values, like String , Number , Boolean , or Any :
See in TypeScript Playground .
Pro: The main benefit of these methods is the ability to dynamically add properties to an object while setting expectations for the possible types of keys and values.
Con: The main disadvantage of this way is that we can’t predict what keys our objects will have, so some references may or may not be defined. An additional disadvantage is that if we decide to define our key signature with type Any , then the object becomes even more unpredictable.
Conditional/Optional properties
This set of object assignment methods shares a common feature: the definition of optional properties. This means the range of possible properties are known but some may not be set. The options in this group include:
- Using optional object properties
- Using the Partial utility type
- Using type assertions
See this example in the TypeScript Playground , or the code block below:
Note: While these options mean that the possible keys are known and may not be set, TypeScript’s compiler won’t validate undefined states when using type assertions. This can lead to unhandled exceptions during runtime. For example, with optional properties and the Partial utility type, name has type string or undefined . Meanwhile, with type assertions, name has type string .
Pro: The advantage of this group of options is that all possible object keys and values are known.
Con: The disadvantage is that while the possible keys are known, we don’t know if they have been set and will have to handle the possibility that they are undefined.
When working with dynamic object properties (especially for using optional properties), type guards can be useful for ensuring type safety and preventing runtime errors. Type guards are a powerful TypeScript feature that allows us to check a variable’s type at runtime and conditionally execute code based on the result.
Recent improvements to index access handling in TypeScript
In TypeScript 5.5, a new improvement called “Control Flow Narrowing for Constant Indexed Accesses” was introduced.
This improvement narrows expressions of the form obj[key] when both obj and key are effectively constant. For example, prior to 5.5, TypeScript would throw an error with the following code. Now, TypeScript can determine that obj[key] is a string after the typeof check, improving type safety and flexibility in similar scenarios:
See in TypeScript playground.
In this article, we explored several ways to dynamically assign properties to TypeScript objects while maintaining type safety. Key approaches include using:
- Object index signatures
- The Record utility type
- The Map data type
- Optional object properties
- Type assertions
- The Partial utility type
Each method offers flexibility in managing dynamic properties while adhering to TypeScript’s strong typing system. Choosing the right approach depends on the use case, whether you prioritize key predictability or type safety.
If you’d like to read more on this subject, please check out my cheatsheet on the seven most-asked TypeScript questions on Stack Overflow, or tweet me any questions . Cheers!
LogRocket : Full visibility into your web and mobile apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.
Try it for free .
Share this:
- Click to share on Twitter (Opens in new window)
- Click to share on Reddit (Opens in new window)
- Click to share on LinkedIn (Opens in new window)
- Click to share on Facebook (Opens in new window)
- #typescript
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Stop guessing about your digital experience with LogRocket
Recent posts:.
Building a background remover with Vue and Transformers.js
Build a real-time image background remover in Vue using Transformers.js and WebGPU for client-side processing with privacy and efficiency.
Managing search parameters in Next.js with nuqs
Optimize search parameter handling in React and Next.js with nuqs for SEO-friendly, shareable URLs and a better user experience.
Data fetching with Remix’s loader function
Learn how Remix enhances SSR performance, simplifies data fetching, and improves SEO compared to client-heavy React apps.
Top 8 Fullstory competitors and alternatives
Explore Fullstory competitors, like LogRocket, to find the best product analytics tool for your digital experience.
3 Replies to "How to dynamically assign properties to an object in TypeScript"
I know this is explicitly for TypeScript, and I think type declarations should always be first. But in general, you can also use a Map object. If it’s really meant to by dynamic, might as well utilize the power of Map.
Great suggestion (updated the article). It’s worth mentioning the weak typing you get by default i.e., with respect to Typescript.
Hi, thanks for your valuable article please consider ‘keyof type’ in TypeScript, and add this useful solution if you are happy have nice time
Leave a Reply Cancel reply
- Underscore.js
- Tensorflow.js
- JS Formatter
- Web Technology
How do I dynamically assign properties to an object in TypeScript?
In TypeScript, we can not assign the properties dynamically to an object directly by using the dot operator and the square brackets syntax which we generally use to assign dynamic properties in Vanilla JavaScript.
JavaScript is a dynamically typed language and the type of a variable is determined at runtime due to which assigning dynamic properties to JavaScript objects does not give any error. On the other hand, TypeScript is a statically typed language, and the type of variable must be predefined in this. Therefore, if you try to assign dynamic properties to a TypeScript object directly using the dot operator and square bracket syntax will give an error.
Defining an object with empty curly ({}) brackets in TypeScript is not considered as an object, it will be considered as empty braces, and assigning properties to it will throw an error. In this article, we will discuss different methods of dynamically assigning a property to an object in TypeScript.
There are three ways of assigning dynamic properties to objects in TypeScript:
Table of Content
By declaring the object with explicit type
By using the index signature of the object, by using the record utility type, using object.defineproperty.
As we know TypeScript is a statically typed language and it expects the explicit type for each variable declared in the code. So, we can declare the object with an explicit type and dynamically assign the properties to an object without any error.
Example: This example shows the declaration of an object with explicit type.
The index signature is also a way of explicitly typing an object but in a different syntax than the simple explicit typing.
Example: This example shows the way of explicitly typing an object using the object index signature.
The Record utility type helps us to explicit type the object and its keys and values in a particular syntax.
Example: The below example will help you to understand the practical use of Record utility type to type an object.
The Object.defineProperty method allows us to define new properties directly on an object or modify existing properties. This method provides more control over property attributes such as configurable, enumerable, and writable.
Similar Reads
- How do I dynamically assign properties to an object in TypeScript? In TypeScript, we can not assign the properties dynamically to an object directly by using the dot operator and the square brackets syntax which we generally use to assign dynamic properties in Vanilla JavaScript. JavaScript is a dynamically typed language and the type of a variable is determined at 3 min read
- How to make object properties immutable in TypeScript ? In this article, we will try to understand how we could make object properties immutable in TypeScript. JavaScript is a highly dynamic and flexible language, hence making object properties in JavaScript immutable is a little bit typical (although we may implement it somehow using a const data type t 2 min read
- How to Convert an Array of Objects into Object in TypeScript ? Converting an array of objects into a single object is a common task in JavaScript and TypeScript programming, especially when you want to restructure data for easier access. In this article, we will see how to convert an array of objects into objects in TypeScript. We are given an array of objects 3 min read
- How to Declare Optional Properties in TypeScript ? The optional properties are the properties that may or may not be present in an object or assigned with a value. You can define the optional properties for different data types in TypeScript like interfaces, type aliases, classes, etc. In TypeScript, you can use the question mark (?) symbol to decla 1 min read
- How to Iterate Over Object Properties in TypeScript In TypeScript, Objects are the fundamental data structures that use key-value pair structures to store the data efficiently. To iterate over them is a common task for manipulating or accessing the stored data. TypeScript is a superset of JavaScript and provides several ways to iterate over object pr 3 min read
- How can I Define an Array of Objects in TypeScript? In TypeScript, the way of defining the arrays of objects is different from JavaScript. Because we need to explicitly type the array at the time of declaration that it will be an Array of objects. In this article, we will discuss the different methods for declaring an array of objects in TypeScript. 6 min read
- How to Cast a JSON Object Inside of TypeScript Class ? JSON objects are commonly used to store and transport data between a server and a client application, or locally in a Node.js project. In TypeScript, objects can be either plain objects or class (constructor) objects. This article explores how to convert JSON objects to TypeScript class instances, e 3 min read
- How to Merge Properties of Two JavaScript Objects Dynamically? Here are two different ways to merge properties of two objects in JavaScript. 1. Using Spread OperatorThe Spread operator allows an iterable to expand in places where 0+ arguments are expected. It is mostly used in the variable array where there is more than 1 value is expected. It allows the privil 1 min read
- How to Sort an Array of Object using a Value in TypeScript ? Sorting an array of objects using a value in TypeScript pertains to the process of arranging an array of objects in a specified order based on a particular property or value contained within each object. The below approaches can be used to sort an array of objects using a value in TypeScript: Table 3 min read
- How to Create Objects with Dynamic Keys in TypeScript ? In TypeScript, objects with dynamic keys are those where the key names are not fixed and can be dynamically determined at runtime. This allows the creation of flexible data structures where properties can be added or accessed using variables, providing more versatile type definitions. These are the 3 min read
- How to Declare Specific Type of Keys in an Object in TypeScript ? In TypeScript, object definitions can include specific key-value types using index signatures. You can declare specific types of keys in an object by using different methods as listed below: Table of Content Using Mapped TypesUsing InterfaceUsing Inline Mapped Types with typeUsing Record Utility Typ 3 min read
- How to Check the Type of an Object in Typescript ? When working with TypeScript, understanding how to check the type of an object is crucial for ensuring type safety and maintaining code integrity. TypeScript, being a statically typed superset of JavaScript, provides several approaches to accomplish this task as listed below. Table of Content Using 3 min read
- How to Dynamically Serialise & Restore ES6 Class Types in JavaScript ? Dynamically serializing and restoring ES6 class types in JavaScript refers to the process of converting instances of ES6 classes into a format (e.g., JSON) that can be stored or transmitted, and then reconstructing those instances from the serialized data, preserving their class structure and behavi 2 min read
- How to Check if an Object is Empty in TypeScript ? In TypeScript, it's common to encounter scenarios where you need to determine if an object is empty or not. An empty object typically means it contains no properties or all its properties are either undefined or null. Below are the methods to check if an object is empty or not in TypeScript: Table o 3 min read
- How to Initialize a TypeScript Object with a JSON-Object ? To initialize a TypeScript Object with a JSON-Object, we have multiple approaches. In this article, we are going to learn how to initialize a TypeScript Object with a JSON-Object. Below are the approaches used to initialize a TypeScript Object with a JSON-Object: Table of Content Object.assign Type 3 min read
- How to Sort Objects in an Array Based on a Property in a Specific Order in TypeScript ? Sorting objects in an array based on a specific property is a common task in software development. TypeScript, with its static typing and powerful features, provides various approaches to accomplish this task efficiently. The below approaches can be used to sort an array of objects in properties. Ta 3 min read
- How to Extend an Interface from a class in TypeScript ? In this article, we will try to understand how we to extend an interface from a class in TypeScript with the help of certain coding examples. Let us first quickly understand how we can create a class as well as an interface in TypeScript using the following mentioned syntaxes: Syntax: This is the sy 3 min read
- How to Sort or Reduce an Object by Key in TypeScript ? Sorting an object by key generally refers to arranging its properties in a specific order, while reducing involves selecting a subset of properties based on provided keys. Different approaches allow developers to perform these operations with flexibility. Below are the approaches used to sort or red 3 min read
- Add an Object to an Array in TypeScript TypeScript allows adding an object to an array that is a common operation when working with collections of data. Below are the approaches to add an object to an array in TypeScript: Table of Content Using the push methodUsing the Spread Operator (...)Using array concatenation (concat)Using Array Uns 6 min read
- Web Technologies
Improve your Coding Skills with Practice
What kind of Experience do you want to share?
How to Add a property to an Object in TypeScript
Last updated: Feb 27, 2024 Reading time · 10 min
# Table of Contents
- Add a property to an Object in TypeScript
- Dynamically add Properties to an Object in TypeScript
- Set an Object's property name from a Variable in TypeScript
- Constructing the object's property name from multiple variables
- Using Object.assign() in TypeScript
# Add a property to an Object in TypeScript
To add a property to an object in TypeScript:
- Mark the property on the interface or type as optional.
- Use the interface to type the object.
- Add the property to the object.
We set the age property on the Person interface to optional .
Now you can initialize the object without the property and set it later on.
If you try to assign a non-numeric value to the age property, you'd get an error.
If you need to make all properties of an object optional, use the Partial utility type.
# Add any property to an object in TypeScript
You can use the Record utility type to add any property of any type to an object.
The Record utility type allows us to enforce the type of an object's values in TypeScript, e.g. type Animal = Record<string, string> .
We used a type of any for the values and a type of string for the keys in the object.
This is very broad and allows us to add any property of any type to the object.
# Add any property but type key-value pairs you know in advance
You can specify the properties and the types in an object that you know about and use the Record utility type to allow the user to add other properties.
The interface we created requires the name and age properties but also extends a type that allows any string properties with values of any type.
This is better than just using the Record utility type with string keys and any values because we get type safety when it comes to the properties we explicitly specified.
Setting a property to the incorrect type causes an error because we've already declared the name property to be of type string in the Animal interface.
I've also written an article on how to get an object's key by value in TS .
# Dynamically add Properties to an Object in TypeScript
Use an index signature to dynamically add properties to an object.
Index signatures are used when we don't know all of the names of a type's properties and the type of their values ahead of time.
The {[key: string]: any} syntax is an index signature in TypeScript and is used when we don't know all the names of a type's properties and the shape of the values ahead of time.
You might also see the index signature {[key: string]: string} in examples. It represents a key-value structure that when indexed with a string returns a value of type string .
I've also written an article on how to dynamically access an object's property .
# Explicitly typing specific properties
If the value of the string keys were set to any in the index signature, you could add properties to the object of any type, since anything is more specific than any .
This is a good way to narrow down the type of some of the properties that you know ahead of time.
For example, if I try to set the age property to a string , the type checker would throw an error because it expects a number .
We've set the age property to have a type of number , so the type checker helps us spot an error in our application.
# Using a union to dynamically add properties to an object
You can also use a union type to dynamically add properties to an object.
The keys in the object can either have a type of string or number .
Both types are allowed and you can use the union | syntax to include as many types as necessary.
If we try to set a property with a different value on the object, we'd get an error.
# Dynamically adding properties to an object with the Record type
The Record utility type constructs an object type whose keys and values are of a specified type.
We typed the object above to have keys of type string and values of type any .
If you know the type of some of the values ahead of time, specify them in an interface for better type safety.
The interface EmployeeData extends from the Record constructed type with string keys and any type values.
If we try to set the role , salary or color properties to an incompatible type, we'd get an error.
# Set an Object's property name from a Variable in TypeScript
Use computed property names to set an object's property name from a variable in TypeScript.
We set an object's property name from a variable using computed properties.
Here is an example that uses a function.
# Constructing the object's property name from multiple variables
The expression between the square brackets gets evaluated, so you could construct the object's property name by using multiple variables or concatenating strings.
You can also use a template literal .
However, notice that TypeScript was not able to type the property in the object as name and instead typed it as a more generic index signature of [x: string] (any string property).
If you are sure about the value the expression will evaluate to, use a type assertion .
Now the object is typed correctly and we can still use the dynamic nature of the computed property names feature.
# Using Object.assign() in TypeScript
To use the Object.assign() method in TypeScript, pass a target object as the first parameter to the method and one or more source objects.
The method will copy the properties from the source objects to the target object.
We used the Object.assign method to merge two source objects into a target object.
The next parameters are source objects - objects containing the properties you want to apply to the target .
# Caveats around using an existing object as the target
In the example, we passed an empty object as the target because you should generally avoid mutating objects as it introduces confusion.
For example, we could've passed obj1 as the target and obj2 as the source.
Note that the target object is changed in place.
This is especially problematic when using TypeScript because obj1 was changed in place but its type is still {name: string} , even though the object contains a country property as well.
# The return type of Object.assign in TypeScript
TypeScript uses an intersection type to type the return value of the Object.assign() method.
In other words, the return value has a type that has all of the members of all of the objects you passed to the Object.assign() method.
# The latter object wins
When you use the Object.assign() method with objects that have the same properties, the properties are overwritten by objects that come later in the parameter list.
Both of the objects in the example have a name property, so the object that is passed later in the parameters order wins.
I've also written an article on how to initialize a typed empty object in TypeScript .
# An alternative to using Object.assign
You should also consider using the spread syntax (...) as a replacement for Object.assign() .
The spread syntax (...) unpacks the properties of the objects into a new object.
This is generally a better approach because you can't shoot yourself in the foot by forgetting to provide an empty object as the first parameter of the Object.assign() method.
You can unpack as many objects as necessary into a new object and if two objects have the same property, the object that comes later wins.
Both of the objects have a name property, so the latter object wins.
# Additional Resources
You can learn more about the related topics by checking out the following tutorials:
- Dynamically access an Object's Property in TypeScript
- Check if a Property exists in an Object in TypeScript
- Check if Value with Unknown Type contains Property in TS
- How to Remove a Property from an Object in TypeScript
- Property is incompatible with index signature in TypeScript
- A spread argument must either have a tuple type or be passed to a rest parameter
- 'this' implicitly has type 'any' error in TypeScript [Fixed]
- Type 'string or null' is not assignable to type string (TS)
- Type Object must have a Symbol.iterator method that returns an iterator
- Type 'string' is not assignable to type in TypeScript
Borislav Hadzhiev
Web Developer
Copyright © 2024 Borislav Hadzhiev
TypeScript Object assign()
In this chapter, we will explore the Object.assign() method in TypeScript. This method copies the properties from one or more source objects to a target object. It returns the target object. This is useful for copying or merging objects.
Table of Contents
1. definition.
The Object.assign() method copies the properties from one or more source objects to a target object. It returns the target object.
- target : The object to which properties are copied.
- sources : One or more objects from which properties are copied.
Return Value
The method returns the target object with properties copied from the source objects.
3. Examples
Let’s look at some examples to understand how Object.assign() works in TypeScript.
Example 1: Basic Usage
This example shows how to copy properties from one object to another.
Example 2: Merging Objects
This example shows how to merge properties from multiple source objects into a target object.
Example 3: Cloning an Object
This example shows how to create a shallow copy of an object.
Example 4: Overwriting Properties
This example shows how properties in the target object are overwritten by properties from the source objects.
Example 5: Handling Undefined and Null Sources
This example shows how Object.assign() handles undefined and null source objects.
Example 6: Copying Symbols
This example shows how to copy symbol properties from a source object to a target object.
Example 7: Nested Objects
This example shows how Object.assign() handles nested objects. It performs a shallow copy, meaning nested objects are not deeply copied.
4. Conclusion
In this chapter, we explored the Object.assign() method in TypeScript, which is used to copy properties from one or more source objects to a target object. We covered its definition, syntax, parameters, return value, and provided several examples to demonstrate its usage. Understanding how to use Object.assign() is essential for copying or merging objects in TypeScript applications.
Related Posts:
What is typescript, setting up typescript environment, writing your first typescript program, typescript basic syntax, typescript vs javascript, typescript variables, typescript let, typescript const, typescript comments, leave a comment cancel reply.
Your email address will not be published. Required fields are marked *
Save my name, email, and website in this browser for the next time I comment.
- Skip to main content
- Skip to search
- Skip to select language
- Sign up for free
- Remember language
- Português (do Brasil)
Object.assign()
Baseline widely available.
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015 .
- See full compatibility
- Report feedback
The Object.assign() static method copies all enumerable own properties from one or more source objects to a target object . It returns the modified target object.
The target object — what to apply the sources' properties to, which is returned after it is modified.
The source object(s) — objects containing the properties you want to apply.
Return value
The target object.
Description
Properties in the target object are overwritten by properties in the sources if they have the same key . Later sources' properties overwrite earlier ones.
The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters . Therefore it assigns properties, versus copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.
For copying property definitions (including their enumerability) into prototypes, use Object.getOwnPropertyDescriptor() and Object.defineProperty() instead.
Both String and Symbol properties are copied.
In case of an error, for example if a property is non-writable, a TypeError is raised, and the target object is changed if any properties are added before the error is raised.
Note: Object.assign() does not throw on null or undefined sources.
Cloning an object
Warning for deep clone.
For deep cloning , we need to use alternatives like structuredClone() , because Object.assign() copies property values.
If the source value is a reference to an object, it only copies the reference value.
Merging objects
Merging objects with same properties.
The properties are overwritten by other objects that have the same properties later in the parameters order.
Copying symbol-typed properties
Properties on the prototype chain and non-enumerable properties cannot be copied, primitives will be wrapped to objects, exceptions will interrupt the ongoing copying task, copying accessors, specifications, browser compatibility.
BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.
- Polyfill of Object.assign in core-js
- Object.defineProperties()
- Enumerability and ownership of properties
- Spread in object literals
DEV Community
Posted on Feb 14, 2023 • Originally published at junedang.com
Object.assign in TypeScript: An Introduction to Converting Classes
Imagine that you are working on calling an API to receive a list of Person. Each Person has their first name, last name and title. Knowing the model received from the backend, you create a model in the frontend side to catch the value received like:
Now you have received the data from the backend, it’s time for rendering it into view. The requirement is to have title, first name and last name ordered in the same row . Your HTML now looks something like this:
Until now, the code looks fine and everything runs as you expected. But a new UI comes and you have to adapt that kind of HTML layout in other components. Things look a little duplicate here so you decide to reuse the template by setting a method in Person type. You change Person type to a class and add a method getInfo so that the template can be reused in your components. The code now looks like this:
By using a class, now your components can reuse the template by calling getInfo() method:
The problem with this approach is that unlike Java, data serialized from JSON to JavaScript code only mapped to fields not to methods and so when you try to run the above code, you are likely to receive an error getInfo is not a function.
In order to solve this problem, Object.assign provides a way to map data to the class constructor. By using Object.assign , you can convert a plain object to a class instance and all the fields in the object will be assigned to the class fields. Therefore, you can call an instance method, in this case getInfo , after mapping the data. You can use Object.assign like this:
Now you can use the person instance to call getInfo method:
This approach helps you to reuse the template and avoid duplicate code.
In this article, you learned how to cast plain object data to a class in TypeScript. If you found it useful, please consider liking and sharing it to help spread the knowledge.
Top comments (0)
Templates let you quickly answer FAQs or store snippets for re-use.
Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .
Hide child comments as well
For further actions, you may consider blocking this person and/or reporting abuse
Cascading form React Native Improved
RamR - Nov 30
Build a Simple Real-Time SBOBET88-Style Website for Beginners with PHP, CSS, and JavaScript
Sbobet88 Dev - Nov 30
Daily JavaScript Challenge #JS-33: Count Unique Elements
DPC - Nov 30
Angular Form Array
Julie Gladden - Nov 29
We're a place where coders share, stay up-to-date and grow their careers.
Was this page helpful?
Object Types
In JavaScript, the fundamental way that we group and pass around data is through objects. In TypeScript, we represent those through object types .
As we’ve seen, they can be anonymous:
or they can be named by using either an interface:
or a type alias:
In all three examples above, we’ve written functions that take objects that contain the property name (which must be a string ) and age (which must be a number ).
Quick Reference
We have cheat-sheets available for both type and interface , if you want a quick look at the important every-day syntax at a glance.
Property Modifiers
Each property in an object type can specify a couple of things: the type, whether the property is optional, and whether the property can be written to.
Optional Properties
Much of the time, we’ll find ourselves dealing with objects that might have a property set. In those cases, we can mark those properties as optional by adding a question mark ( ? ) to the end of their names.
In this example, both xPos and yPos are considered optional. We can choose to provide either of them, so every call above to paintShape is valid. All optionality really says is that if the property is set, it better have a specific type.
We can also read from those properties - but when we do under strictNullChecks , TypeScript will tell us they’re potentially undefined .
In JavaScript, even if the property has never been set, we can still access it - it’s just going to give us the value undefined . We can just handle undefined specially by checking for it.
Note that this pattern of setting defaults for unspecified values is so common that JavaScript has syntax to support it.
Here we used a destructuring pattern for paintShape ’s parameter, and provided default values for xPos and yPos . Now xPos and yPos are both definitely present within the body of paintShape , but optional for any callers to paintShape .
Note that there is currently no way to place type annotations within destructuring patterns. This is because the following syntax already means something different in JavaScript. ts function draw ({ shape : Shape , xPos : number = 100 /*...*/ }) { render ( shape ); Cannot find name 'shape'. Did you mean 'Shape'? 2552 Cannot find name 'shape'. Did you mean 'Shape'? render ( xPos ); Cannot find name 'xPos'. 2304 Cannot find name 'xPos'. } Try In an object destructuring pattern, shape: Shape means “grab the property shape and redefine it locally as a variable named Shape .” Likewise xPos: number creates a variable named number whose value is based on the parameter’s xPos .
readonly Properties
Properties can also be marked as readonly for TypeScript. While it won’t change any behavior at runtime, a property marked as readonly can’t be written to during type-checking.
Using the readonly modifier doesn’t necessarily imply that a value is totally immutable - or in other words, that its internal contents can’t be changed. It just means the property itself can’t be re-written to.
It’s important to manage expectations of what readonly implies. It’s useful to signal intent during development time for TypeScript on how an object should be used. TypeScript doesn’t factor in whether properties on two types are readonly when checking whether those types are compatible, so readonly properties can also change via aliasing.
Using mapping modifiers , you can remove readonly attributes.
Index Signatures
Sometimes you don’t know all the names of a type’s properties ahead of time, but you do know the shape of the values.
In those cases you can use an index signature to describe the types of possible values, for example:
Above, we have a StringArray interface which has an index signature. This index signature states that when a StringArray is indexed with a number , it will return a string .
Only some types are allowed for index signature properties: string , number , symbol , template string patterns, and union types consisting only of these.
It is possible to support multiple types of indexers. Note that when using both `number` and `string` indexers, the type returned from a numeric indexer must be a subtype of the type returned from the string indexer. This is because when indexing with a number , JavaScript will actually convert that to a string before indexing into an object. That means that indexing with 100 (a number ) is the same thing as indexing with "100" (a string ), so the two need to be consistent.
While string index signatures are a powerful way to describe the “dictionary” pattern, they also enforce that all properties match their return type. This is because a string index declares that obj.property is also available as obj["property"] . In the following example, name ’s type does not match the string index’s type, and the type checker gives an error:
However, properties of different types are acceptable if the index signature is a union of the property types:
Finally, you can make index signatures readonly in order to prevent assignment to their indices:
You can’t set myArray[2] because the index signature is readonly .
Excess Property Checks
Where and how an object is assigned a type can make a difference in the type system. One of the key examples of this is in excess property checking, which validates the object more thoroughly when it is created and assigned to an object type during creation.
Notice the given argument to createSquare is spelled colour instead of color . In plain JavaScript, this sort of thing fails silently.
You could argue that this program is correctly typed, since the width properties are compatible, there’s no color property present, and the extra colour property is insignificant.
However, TypeScript takes the stance that there’s probably a bug in this code. Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error:
Getting around these checks is actually really simple. The easiest method is to just use a type assertion:
However, a better approach might be to add a string index signature if you’re sure that the object can have some extra properties that are used in some special way. If SquareConfig can have color and width properties with the above types, but could also have any number of other properties, then we could define it like so:
Here we’re saying that SquareConfig can have any number of properties, and as long as they aren’t color or width , their types don’t matter.
One final way to get around these checks, which might be a bit surprising, is to assign the object to another variable: Since assigning squareOptions won’t undergo excess property checks, the compiler won’t give you an error:
The above workaround will work as long as you have a common property between squareOptions and SquareConfig . In this example, it was the property width . It will however, fail if the variable does not have any common object property. For example:
Keep in mind that for simple code like above, you probably shouldn’t be trying to “get around” these checks. For more complex object literals that have methods and hold state, you might need to keep these techniques in mind, but a majority of excess property errors are actually bugs.
That means if you’re running into excess property checking problems for something like option bags, you might need to revise some of your type declarations. In this instance, if it’s okay to pass an object with both a color or colour property to createSquare , you should fix up the definition of SquareConfig to reflect that.
Extending Types
It’s pretty common to have types that might be more specific versions of other types. For example, we might have a BasicAddress type that describes the fields necessary for sending letters and packages in the U.S.
In some situations that’s enough, but addresses often have a unit number associated with them if the building at an address has multiple units. We can then describe an AddressWithUnit .
This does the job, but the downside here is that we had to repeat all the other fields from BasicAddress when our changes were purely additive. Instead, we can extend the original BasicAddress type and just add the new fields that are unique to AddressWithUnit .
The extends keyword on an interface allows us to effectively copy members from other named types, and add whatever new members we want. This can be useful for cutting down the amount of type declaration boilerplate we have to write, and for signaling intent that several different declarations of the same property might be related. For example, AddressWithUnit didn’t need to repeat the street property, and because street originates from BasicAddress , a reader will know that those two types are related in some way.
interface s can also extend from multiple types.
Intersection Types
interface s allowed us to build up new types from other types by extending them. TypeScript provides another construct called intersection types that is mainly used to combine existing object types.
An intersection type is defined using the & operator.
Here, we’ve intersected Colorful and Circle to produce a new type that has all the members of Colorful and Circle .
Interface Extension vs. Intersection
We just looked at two ways to combine types which are similar, but are actually subtly different. With interfaces, we could use an extends clause to extend from other types, and we were able to do something similar with intersections and name the result with a type alias. The principal difference between the two is how conflicts are handled, and that difference is typically one of the main reasons why you’d pick one over the other between an interface and a type alias of an intersection type.
If interfaces are defined with the same name, TypeScript will attempt to merge them if the properties are compatible. If the properties are not compatible (i.e., they have the same property name but different types), TypeScript will raise an error.
In the case of intersection types, properties with different types will be merged automatically. When the type is used later, TypeScript will expect the property to satisfy both types simultaneously, which may produce unexpected results.
For example, the following code will throw an error because the properties are incompatible:
In contrast, the following code will compile, but it results in a never type:
In this case, Staff would require the name property to be both a string and a number, which results in property being of type never .
Generic Object Types
Let’s imagine a Box type that can contain any value - string s, number s, Giraffe s, whatever.
Right now, the contents property is typed as any , which works, but can lead to accidents down the line.
We could instead use unknown , but that would mean that in cases where we already know the type of contents , we’d need to do precautionary checks, or use error-prone type assertions.
One type safe approach would be to instead scaffold out different Box types for every type of contents .
But that means we’ll have to create different functions, or overloads of functions, to operate on these types.
That’s a lot of boilerplate. Moreover, we might later need to introduce new types and overloads. This is frustrating, since our box types and overloads are all effectively the same.
Instead, we can make a generic Box type which declares a type parameter .
You might read this as “A Box of Type is something whose contents have type Type ”. Later on, when we refer to Box , we have to give a type argument in place of Type .
Think of Box as a template for a real type, where Type is a placeholder that will get replaced with some other type. When TypeScript sees Box<string> , it will replace every instance of Type in Box<Type> with string , and end up working with something like { contents: string } . In other words, Box<string> and our earlier StringBox work identically.
Box is reusable in that Type can be substituted with anything. That means that when we need a box for a new type, we don’t need to declare a new Box type at all (though we certainly could if we wanted to).
This also means that we can avoid overloads entirely by instead using generic functions .
It is worth noting that type aliases can also be generic. We could have defined our new Box<Type> interface, which was:
by using a type alias instead:
Since type aliases, unlike interfaces, can describe more than just object types, we can also use them to write other kinds of generic helper types.
We’ll circle back to type aliases in just a little bit.
The Array Type
Generic object types are often some sort of container type that work independently of the type of elements they contain. It’s ideal for data structures to work this way so that they’re re-usable across different data types.
It turns out we’ve been working with a type just like that throughout this handbook: the Array type. Whenever we write out types like number[] or string[] , that’s really just a shorthand for Array<number> and Array<string> .
Much like the Box type above, Array itself is a generic type.
Modern JavaScript also provides other data structures which are generic, like Map<K, V> , Set<T> , and Promise<T> . All this really means is that because of how Map , Set , and Promise behave, they can work with any sets of types.
The ReadonlyArray Type
The ReadonlyArray is a special type that describes arrays that shouldn’t be changed.
Much like the readonly modifier for properties, it’s mainly a tool we can use for intent. When we see a function that returns ReadonlyArray s, it tells us we’re not meant to change the contents at all, and when we see a function that consumes ReadonlyArray s, it tells us that we can pass any array into that function without worrying that it will change its contents.
Unlike Array , there isn’t a ReadonlyArray constructor that we can use.
Instead, we can assign regular Array s to ReadonlyArray s.
Just as TypeScript provides a shorthand syntax for Array<Type> with Type[] , it also provides a shorthand syntax for ReadonlyArray<Type> with readonly Type[] .
One last thing to note is that unlike the readonly property modifier, assignability isn’t bidirectional between regular Array s and ReadonlyArray s.
Tuple Types
A tuple type is another sort of Array type that knows exactly how many elements it contains, and exactly which types it contains at specific positions.
Here, StringNumberPair is a tuple type of string and number . Like ReadonlyArray , it has no representation at runtime, but is significant to TypeScript. To the type system, StringNumberPair describes arrays whose 0 index contains a string and whose 1 index contains a number .
If we try to index past the number of elements, we’ll get an error.
We can also destructure tuples using JavaScript’s array destructuring.
Tuple types are useful in heavily convention-based APIs, where each element’s meaning is “obvious”. This gives us flexibility in whatever we want to name our variables when we destructure them. In the above example, we were able to name elements 0 and 1 to whatever we wanted. However, since not every user holds the same view of what’s obvious, it may be worth reconsidering whether using objects with descriptive property names may be better for your API.
Other than those length checks, simple tuple types like these are equivalent to types which are versions of Array s that declare properties for specific indexes, and that declare length with a numeric literal type.
Another thing you may be interested in is that tuples can have optional properties by writing out a question mark ( ? after an element’s type). Optional tuple elements can only come at the end, and also affect the type of length .
Tuples can also have rest elements, which have to be an array/tuple type.
- StringNumberBooleans describes a tuple whose first two elements are string and number respectively, but which may have any number of boolean s following.
- StringBooleansNumber describes a tuple whose first element is string and then any number of boolean s and ending with a number .
- BooleansStringNumber describes a tuple whose starting elements are any number of boolean s and ending with a string then a number .
A tuple with a rest element has no set “length” - it only has a set of well-known elements in different positions.
Why might optional and rest elements be useful? Well, it allows TypeScript to correspond tuples with parameter lists. Tuples types can be used in rest parameters and arguments , so that the following:
is basically equivalent to:
This is handy when you want to take a variable number of arguments with a rest parameter, and you need a minimum number of elements, but you don’t want to introduce intermediate variables.
readonly Tuple Types
One final note about tuple types - tuple types have readonly variants, and can be specified by sticking a readonly modifier in front of them - just like with array shorthand syntax.
As you might expect, writing to any property of a readonly tuple isn’t allowed in TypeScript.
Tuples tend to be created and left un-modified in most code, so annotating types as readonly tuples when possible is a good default. This is also important given that array literals with const assertions will be inferred with readonly tuple types.
Here, distanceFromOrigin never modifies its elements, but expects a mutable tuple. Since point ’s type was inferred as readonly [3, 4] , it won’t be compatible with [number, number] since that type can’t guarantee point ’s elements won’t be mutated.
More on Functions
Learn about how Functions work in TypeScript.
Creating Types from Types
An overview of the ways in which you can create more types from existing types.
The TypeScript docs are an open source project. Help us improve these pages by sending a Pull Request ❤
Last updated: Nov 25, 2024
IMAGES
VIDEO
COMMENTS
Object.assign works the best when you have flatter objects. If you are combining two nested objects that contain nullable properties, you can end up overwriting truthy values with undefined. If you watch out for the order of the Object.assign arguments, you should be fine.
In this article, we explored several ways to dynamically assign properties to TypeScript objects while maintaining type safety. Key approaches include using: Object index signatures; The Record utility type; The Map data type; Optional object properties; Type assertions; The Partial utility type
The Object.assign() method is used to copy the values and properties from one or more source objects to a target object. It invokes getters and setters since it uses both [[Get]] on the source and [[Set]] on the target.
To use the Object.assign() method in TypeScript, pass a target object as the first parameter to the method and one or more source objects. The method will copy the properties from the source objects to the target object.
In this chapter, we explored the Object.assign() method in TypeScript, which is used to copy properties from one or more source objects to a target object. We covered its definition, syntax, parameters, return value, and provided several examples to demonstrate its usage.
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 ...
The Object.assign() static method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.
By using Object.assign, you can convert a plain object to a class instance and all the fields in the object will be assigned to the class fields. Therefore, you can call an instance method, in this case getInfo , after mapping the data.
I want to use Object.assign to merge some changes with an old object to create a new object (as is common practice in JS when following immutable data patterns) and have TypeScript validate that the parts and the result are correct, but it seems TypeScript allows anything through without an error.
Where and how an object is assigned a type can make a difference in the type system. One of the key examples of this is in excess property checking, which validates the object more thoroughly when it is created and assigned to an object type during creation.