HiveBrain v1.2.0
Get Started
← Back to all entries
snippettypescriptCritical

How do I dynamically assign properties to an object in TypeScript?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
typescriptobjecthowpropertiesdynamicallyassign

Problem

If I wanted to programmatically assign a property to an object in Javascript, I would do it like this:

var obj = {};
obj.prop = "value";


But in TypeScript, this generates an error:

The property 'prop' does not exist on value of type '{}'

How do I assign any new property to an object in TypeScript?

Solution

Index signatures

It is possible to denote obj as any, but that defeats the whole purpose of using typescript. obj = {} implies obj is an Object. Marking it as any makes no sense. To accomplish the desired consistency an interface could be defined as follows, using an index signature

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};


OR to make it compact:

var obj: {[k: string]: any} = {};


LooseObject can accept fields with any string as key and any type as value.

obj.prop = "value";
obj.prop2 = 88;


The real elegance of this solution is that you can include typesafe fields in the interface.

interface MyType {
    typesafeProp1?: number,
    requiredProp1: string,
    [key: string]: any
}

var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number

obj.prop = "value";
obj.prop2 = 88;


Record utility type

Update (August 2020): @transang brought up the Record utility type in comments

Record is a Utility type in typescript. It is a much cleaner alternative for key-value pairs where property-names are not known.
It's worth noting that Record is a named alias to {[k: Keys]: Type} where Keys and Type are generics.
IMO, this makes it worth mentioning here

For comparison,

var obj: {[k: string]: any} = {};


becomes

var obj: Record = {}


MyType can now be defined by extending Record type

interface MyType extends Record {
    typesafeProp1?: number,
    requiredProp1: string,
}


While this answers the Original question, the answer here by @GreeneCreations might give another perspective on how to approach the problem.

Code Snippets

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};
var obj: {[k: string]: any} = {};
obj.prop = "value";
obj.prop2 = 88;
interface MyType {
    typesafeProp1?: number,
    requiredProp1: string,
    [key: string]: any
}

var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number

obj.prop = "value";
obj.prop2 = 88;
var obj: {[k: string]: any} = {};

Context

Stack Overflow Q#12710905, score: 1173

Revisions (0)

No revisions yet.