Type definition in object literal in TypeScript

Typescript

Typescript Problem Overview


In TypeScript classes it's possible to declare types for properties, for example:

class className {
  property: string;
};

How do declare the type of a property in an object literal?

I've tried the following code but it doesn't compile:

var obj = {
  property: string;
};

I'm getting the following error:

> The name 'string' does not exist in the current scope

Am I doing something wrong or is this a bug?

Typescript Solutions


Solution 1 - Typescript

You're pretty close, you just need to replace the = with a :. You can use an object type literal (see spec section 3.5.3) or an interface. Using an object type literal is close to what you have:

var obj: { property: string; } = { property: "foo" };

But you can also use an interface

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };

Solution 2 - Typescript

Update 2019-05-15 (Improved Code Pattern as Alternative)

After many years of using const and benefiting from more functional code, I would recommend against using the below in most cases. (When building objects, forcing the type system into a specific type instead of letting it infer types is often an indication that something is wrong).

Instead I would recommend using const variables as much as possible and then compose the object as the final step:

const id = GetId();
const hasStarted = true;
...
const hasFinished = false;
...
return {hasStarted, hasFinished, id};
  • This will properly type everything without any need for explicit typing.
  • There is no need to retype the field names.
  • This leads to the cleanest code from my experience.
  • This allows the compiler to provide more state verification (for example, if you return in multiple locations, the compiler will ensure the same type of object is always returned - which encourages you to declare the whole return value at each position - giving a perfectly clear intention of that value).
Addition 2020-02-26

If you do actually need a type that you can be lazily initialized: Mark it is a nullable union type (null or Type). The type system will prevent you from using it without first ensuring it has a value.

In tsconfig.json, make sure you enable strict null checks:

"strictNullChecks": true

Then use this pattern and allow the type system to protect you from accidental null/undefined access:



const state = {
    instance: null as null | ApiService,
    // OR
    // instance: undefined as undefined | ApiService,

};

const useApi = () => {
    // If I try to use it here, the type system requires a safe way to access it

    // Simple lazy-initialization 
    const api = state?.instance ?? (state.instance = new ApiService());
    api.fun();

    // Also here are some ways to only access it if it has value:

    // The 'right' way: Typescript 3.7 required
    state.instance?.fun();

    // Or the old way: If you are stuck before Typescript 3.7
    state.instance && state.instance.fun();

    // Or the long winded way because the above just feels weird
    if (state.instance) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans way
    if (state.instance != null) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans 
    // AND I was told to always use triple === in javascript even with null checks way
    if (state.instance !== null && state.instance !== undefined) { state.instance.fun(); }
};

class ApiService {
    fun() {
        // Do something useful here
    }
}

Do not do the below in 99% of cases:
Update 2016-02-10 - To Handle TSX (Thanks @Josh)

Use the as operator for TSX.

var obj = {
    property: null as string
};

A longer example:

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};
Original Answer

Use the cast operator to make this succinct (by casting null to the desired type).

var obj = {
    property: <string> null
};

A longer example:

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};

This is much better than having two parts (one to declare types, the second to declare defaults):

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};

Solution 3 - Typescript

I'm surprised that no-one's mentioned this but you could just create an interface called ObjectLiteral, that accepts key: value pairs of type string: any:

interface ObjectLiteral {
  [key: string]: any;
}

Then you'd use it, like this:

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};

An added bonus is that you can re-use this interface many times as you need, on as many objects you'd like.

Good luck.

Solution 4 - Typescript

You could use predefined utility type Record<Keys, Type> :

const obj: Record<string, string> = {
  property: "value",
};

It allows to specify keys for your object literal:

type Keys = "prop1" | "prop2"

const obj: Record<Keys, string> = {
  prop1: "Hello",
  prop2: "Aloha",
  something: "anything" // TS Error: Type '{ prop1: string; prop2: string; something: string; }' is not assignable to type 'Record<Keys, string>'.
                        //   Object literal may only specify known properties, and 'something' does not exist in type 'Record<Keys, string>'.
};

And a type for the property value:

type Keys = "prop1" | "prop2"
type Value = "Hello" | "Aloha"

const obj1: Record<Keys, Value> = {
  prop1: "Hello",
  prop2: "Hey", // TS Error: Type '"Hey"' is not assignable to type 'Value'.
};

Solution 5 - Typescript

If you're trying to write a type annotation, the syntax is:

var x: { property: string; } = { property: 'hello' };

If you're trying to write an object literal, the syntax is:

var x = { property: 'hello' };

Your code is trying to use a type name in a value position.

Solution 6 - Typescript

If you're trying to add typings to a destructured object literal, for example in arguments to a function, the syntax is:

function foo({ bar, baz }: { bar: boolean, baz: string }) {
  // ...
}

foo({ bar: true, baz: 'lorem ipsum' });

Solution 7 - Typescript

In TypeScript if we are declaring object then we'd use the following syntax:

[access modifier] variable name : { /* structure of object */ }

For example:

private Object:{ Key1: string, Key2: number }

Solution 8 - Typescript

// Use ..

const Per = {
  name: 'HAMZA',
  age: 20,
  coords: {
    tele: '09',
    lan: '190'
  },
  setAge(age: Number): void {
    this.age = age;
  },
  getAge(): Number {
    return age;
  }
};
const { age, name }: { age: Number; name: String } = Per;
const {
  coords: { tele, lan }
}: { coords: { tele: String; lan: String } } = Per;

console.log(Per.getAge());

Solution 9 - Typescript

This is what I'm doing in 2021 with TypeScript 4.5:

const sm = {
  reg: {} as ServiceWorkerRegistration,
  quantum: null as number | null,
  currentCacheName: '' as string, // superfluous
  badSWTimer: 0 as number, // superfluous
}

This is not just a value cast, but works the same as an interface definition, for the object properties that is.

Update: I included two superfluous typings as an example. That is, these typings can be inferred automatically and thus, would not generate compiler errors.

Source: 4.4 Playground

Solution 10 - Typescript

In your code:

var obj = {
  myProp: string;
};

You are actually creating a object literal and assigning the variable string to the property myProp. Although very bad practice this would actually be valid TS code (don't use this!):

var string = 'A string';

var obj = {
  property: string
};

However, what you want is that the object literal is typed. This can be achieved in various ways:

Interface:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };

Type alias:

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };

Object type literal:

var obj: { property: string; } = { property: "Mystring" };

Solution 11 - Typescript

Beware. It may seem obvious to some, but the type declaration:

const foo: TypeName = {}

is not the same compared to casting with as:

const foo = {} as TypeName

despite the suggestions to use it on other answers.

Example:

Thanks, type-safety!:

const foo: { [K in 'open' | 'closed']: string } = {}
// ERROR: TS2739: Type '{}' is missing the following properties from type '{ open: string; closed: string; }': open, closed

Goodbye, type-safety!:

const foo = {} as { [K in 'open' | 'closed']: string }
// No error

Solution 12 - Typescript

  1. create a type using type keyword
type ObjType = {
  property: string;
}

and then you can use it to bind your object to accept this type only, like below.

const obj: ObjType = {
property: "TypeScript"
}

Solution 13 - Typescript

Just to extend @RickLove's reply...

This works great, as you only need to define the type that cannot be inferred:

const initialState = { 
   user: undefined as User | undefined, 
   userLoading: false
}; 

and it transpiles to this js code:

const initialState = { 
   user: undefined, 
   userLoading: false
};  

And if you need to extract it into a type, you can just do this:

export type InitState = typeof initialState;

Solution 14 - Typescript

Convert Object Literal into Type With DRY

Just do:

const myObject = {
   hello: 'how are you',
   hey: 'i am fine thank you'
}
type myObjectType = keyof typeof MyObject

Job done!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDace ZarinaView Question on Stackoverflow
Solution 1 - TypescriptBrian TerlsonView Answer on Stackoverflow
Solution 2 - TypescriptRick LoveView Answer on Stackoverflow
Solution 3 - TypescriptLogicalBranchView Answer on Stackoverflow
Solution 4 - TypescriptstreletssView Answer on Stackoverflow
Solution 5 - TypescriptRyan CavanaughView Answer on Stackoverflow
Solution 6 - TypescriptEgorView Answer on Stackoverflow
Solution 7 - Typescriptmukund patelView Answer on Stackoverflow
Solution 8 - TypescriptHamza IbrahimView Answer on Stackoverflow
Solution 9 - TypescriptRay FossView Answer on Stackoverflow
Solution 10 - TypescriptWillem van der VeenView Answer on Stackoverflow
Solution 11 - TypescriptVladView Answer on Stackoverflow
Solution 12 - TypescriptAkhil SharmaView Answer on Stackoverflow
Solution 13 - TypescriptZomanView Answer on Stackoverflow
Solution 14 - TypescriptCarbonDryView Answer on Stackoverflow