Nahush Farkande
Nahush Farkande

Reputation: 5656

Generic Object type in typescript

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)

Upvotes: 89

Views: 132308

Answers (6)

Experimenter
Experimenter

Reputation: 2477

Answer:

From ESLint hint:

  • If you want a type meaning "any object", you probably want object.

So the alternative is:

type GenericObject = object;

Or just use object directly where its needed. Note that letter casing is crucial since the Object type signifies "any non-nullish value" and might be discouraged.


Bonus:

This solution: type GenericObject = { [key: string]: unknown }; might not be the best option if you have a class data structure as it might lead to the errors:

Argument of type 'DummyClass' is not assignable to parameter of type 'GenericObject'.

Index signature for type 'string' is missing in type 'DummyClass'

Upvotes: 1

Deniz Tetik
Deniz Tetik

Reputation: 560

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:

Upvotes: 5

Josh Leslie
Josh Leslie

Reputation: 237

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 !

Upvotes: 0

JaredMcAteer
JaredMcAteer

Reputation: 22545

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.

Upvotes: 90

Bill Barnes
Bill Barnes

Reputation: 342

As of TypeScript 2.2 you can use

let myVariable: object;

Edit: Here's an example:

let myVariable: object = { fun: 1 };

Upvotes: -1

Nitzan Tomer
Nitzan Tomer

Reputation: 164357

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)

Upvotes: 121

Related Questions