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

Index types

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.

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<Keys,Type> utility type

Update (August 2020): @transang brought this up in comments

Record<Keys,Type> 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<Keys,Type> 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<string,any> = {}

MyType can now be defined by extending Record type

interface MyType extends Record<string,any> {
    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.


Or all in one go:

  var obj:any = {}
  obj.prop = 5;

This solution is useful when your object has Specific Type. Like when obtaining the object to other source.

let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.

I tend to put any on the other side i.e. var foo:IFoo = <any>{}; So something like this is still typesafe:

interface IFoo{
    bar:string;
    baz:string;
    boo:string;     
}

// How I tend to intialize 
var foo:IFoo = <any>{};

foo.bar = "asdf";
foo.baz = "boo";
foo.boo = "boo";

// the following is an error, 
// so you haven't lost type safety
foo.bar = 123; 

Alternatively you can mark these properties as optional:

interface IFoo{
    bar?:string;
    baz?:string;
    boo?:string;    
}

// Now your simple initialization works
var foo:IFoo = {};

Try it online

Tags:

Typescript