Generic Object type in typescript

TypescriptTypes

Typescript Problem Overview


In typescript is there any way to assign a variable a generic object type. Here's what I mean by 'generic Object type'

let myVariable: GenericObject = 1 // Should throw an error
                              = 'abc' // Should throw an error
                              = {} // OK
                              = {name: 'qwerty'} //OK

i.e. It should only allow javascript objects to be assigned to the variable and no other type of data(number, string, boolean)

Typescript Solutions


Solution 1 - Typescript

Sure thing:

type GenericObject = { [key: string]: any };

let myVariable1: GenericObject = 1; // Type 'number' is not assignable to type '{ [key: string]: any; }'
let myVariable2: GenericObject = 'abc'; // Type 'string' is not assignable to type '{ [key: string]: any; }'
let myVariable3: GenericObject = {} // OK
let myVariable4: GenericObject = {name: 'qwerty'} //OK

(code in playground)

Solution 2 - Typescript

Typescript 2.1+ also has has a utility type, Record<K, T>, you can use instead of making your own definition

const myObj: Record<string, any>;

I like to use the style described in top answer when I can give a meaningful name to key but if it's not really as obvious or necessary Record is a great option.

Solution 3 - Typescript

As of TypeScript 2.2 you can use

let myVariable: object;

Edit: Here's an example:

let myVariable: object = { fun: 1 };

Solution 4 - Typescript

A bit of a tangent since I haven't found a similar answer elsewhere, from @JaredMcAteer here, using record helped me with mixing enums + objects.

enum FOO_ENUM {
  BAR = 'BAZ';
}

type FOO_OBJECT_TYPE = { ... };

const BIZ_OBJECT: Record<FOO_ENUM, FOO_OBJECT_TYPE> = {
  [FOO_ENUM.BAR]: { ... }
}

Where before I was typing BIZ_OBJECT as
BIZ_OBJECT: {[type: string]: FOO_OBJECT}
which allowed something like BIZ_OBJECT.asd, now only a key from FOO_ENUM can be used, e.g.

  • BIZ_OBJECT.BAZ // { ... }
  • BIZ_OBJECT.asd // Property 'asd' does not exist on type ...
  • BIZ_OBJECT[FOO_ENUM.BAR] // { ... }
  • BIZ_OBJECT[FOO_ENUM.asd] // Property 'asd' does not ...
  • BIZ_OBJECT[FOO_ENUM['asd']] // ! not caught !

Solution 5 - Typescript

As of TypeScript 3.0+ this is the type-safe answer:

type GenericObject = Record<string, unknown>;

And since you'll be getting type protection, you need to do a type check before using a property of the object:

const obj: GenericObject = {
  someFn: () => 'string return';
}

if (typeof obj.someFn === 'function') {
  obj.someFn();
}

TypeScript will not complain about any of course but it is technically not the "generic object type".

More info on the differences between any and unknown:

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
QuestionNahush FarkandeView Question on Stackoverflow
Solution 1 - TypescriptNitzan TomerView Answer on Stackoverflow
Solution 2 - TypescriptJaredMcAteerView Answer on Stackoverflow
Solution 3 - TypescriptBill BarnesView Answer on Stackoverflow
Solution 4 - TypescriptJosh LeslieView Answer on Stackoverflow
Solution 5 - TypescriptDeniz AslanView Answer on Stackoverflow