Defining an array of objects in Typescript


The most simple way to define an array of objects in typescript is by placing brackets after an interface, you can do this either by defining a named interface or inline.

While you can define an array (or other types) inline, it's recommended to create a named interface that you can reference in other parts of your application.

With an inline type alias

Say we want to have an array of farm animals, we can simply define the array type inline:

const animalsArray: {
  name: string;
  size: "small" | "medium" | "large";
}[] = [
  { name: "chicken", size: "small" },
  { name: "pig", size: "medium" },
  { name: "cow", size: "large" },

Note that we add the square brackets [] after the type to indicate that animalsArray should be an array of that type. But this leads to slightly cumbersome code and an inability to reuse our type definition unless the type is inferred down the line.

With an interface

With a named interface we can reuse the animal type:

interface Animal {
  name: string;
  size: "small";

const animalsArray: Animal[] = [
  { name: "chicken", size: "small" },
  { name: "pig", size: "medium" },
  { name: "cow", size: "large" },

This is much cleaner and now we can do things like import / export our interface to different files where we might reference the same data structure.

Should you use type or interface?

You may have noticed that interfaces and types do roughly the same thing when applied to simple object types. And it is true that for the most part they can be used interchangeably for these simple cases. So the question then is, what are the difference, and which should I use?

Types can be used to alias more complicated types, whereas interfaces are more for basic type structure, eg. of an object or class. Interfaces can be used to type functions / arrays, but typically types are used for this because of easier to read syntax. A few other differences:

  1. You cannot use implements on a type that is a union between multiple types, since the class won't know which methods / values have to be implemented
  2. Similarly, you cannot declare an interface that extends a union type. This is because, like classes, the shape of an interface needs to be specified at declaration time and not inferred by later usage.
  3. Typescript merges declarations of interfaces with the same name

You can read the typescript doc for a more expanded understanding of what interfaces are and how they are meant to be used. Essentially interfaces have the advantage of being able to merge multiple declarations with the same name, but are less flexible when it comes to things like union types / advanced types:

The declaration merging is somewhat helpful for when you author a library and want the declarations to automatically be merged in consumers of your library's functions, that way you can eg. extend those interfaces with extra things when consuming them.

So which one to use?

I basically default to using type always, for react props and just about everything else unless I am intending to create a public api that will be consumed eg from an npm package.