Question

Creating Empty Typed Arrays in TypeScript

typescriptjavascriptarrays

Question

I am building a simple logic game called “Three of a Crime” in TypeScript. How can I create an empty array that is typed to contain Criminal objects?

I tried:

var arr = Criminal[];

This produced the error: Check format of expression term.

I also tried:

var arr: Criminal = [];

This produced an error because an empty array cannot be assigned to a single Criminal value. What is the correct TypeScript syntax for creating an empty typed array?

Short Answer

You will learn how TypeScript distinguishes one object from an array of objects, how to initialize an empty typed array, and how to safely create arrays with an intended size.

Concept

Criminal means one value whose type is Criminal.

Criminal[] means an array whose elements are Criminal values.

To create an empty typed array, put the array type after the variable name and assign an array value:

const criminals: Criminal[] = [];

The : Criminal[] part is a type annotation. It tells TypeScript what may be stored in the array. The [] part is an array expression: it creates an empty array at runtime.

This distinction matters because TypeScript types are mostly checked during development and then removed when JavaScript is produced. At runtime, JavaScript needs an actual value such as []; it cannot execute a type like Criminal[].

Mental Model

Think of Criminal as the label for one evidence folder.

Criminal[] is the label for a storage box that may hold many evidence folders.

  • const criminal: Criminal = ... expects one folder.
  • const criminals: Criminal[] = [] creates an empty box for folders.

Writing Criminal[] by itself is only a label describing a kind of box. It is not the box itself. To create the box, use [].

Take Quiz

Syntax and Examples

Use either Type[] or the generic Array<Type> syntax.

interface Criminal {
  name: string;
  motive: string;
}

const criminals: Criminal[] = [];

criminals.push({ name: "Alex", motive: "Money" });
criminals.push({ name: "Blair", motive: "Revenge" });

console.log(criminals);

criminals starts empty, but TypeScript permits only values matching the Criminal shape.

criminals.push({ name: "Casey" });
// Error: Property 'motive' is missing.

The equivalent generic form is:

const criminals: Array<Criminal> = [];

For most simple element types, Criminal[] is shorter and more common.

Step by Step Execution

Consider this code:

interface Criminal {
  name: string;
  motive: string;
}

const suspects: Criminal[] = [];

suspects.push({ name: "Morgan", motive: "Jealousy" });

const firstSuspect = suspects[0];
console.log(firstSuspect.name);
  1. The interface defines the required shape of a Criminal.
  2. const suspects: Criminal[] = [] creates an empty JavaScript array and records that it should contain Criminal objects.
  3. push adds an object with both required properties, so TypeScript accepts it.
  4. suspects[0] reads the first object from the array.
  5. The program prints Morgan.

With noUncheckedIndexedAccess enabled in tsconfig.json, TypeScript treats suspects[0] as possibly undefined, because an array index may not exist. Check it before using it:

const firstSuspect = suspects[0];

if (firstSuspect) {
  console.log(firstSuspect.name);
}

Real World Use Cases

Typed arrays are useful whenever a program collects multiple values of one kind:

  • Game state: store suspects, clues, cards, turns, or board cells.
  • API data: represent a list returned from /users or /orders.
  • Form validation: collect validation messages as string[].
  • Data processing: build a Transaction[] while reading a file or database rows.
  • UI rendering: store Product[] and render one item per product.

Example: collecting validation errors.

const errors: string[] = [];

if (!email.includes("@")) {
  errors.push("Enter a valid email address.");
}

if (password.length < 8) {
  errors.push("Password must contain at least 8 characters.");
}
Take Quiz

Real Codebase Usage

In real projects, typed arrays commonly appear as function return types, object properties, and API models.

Return a list from a function

function findSuspiciousCriminals(criminals: Criminal[]): Criminal[] {
  return criminals.filter((criminal) => criminal.motive !== "None");
}

Store an initially empty list in application state

class GameState {
  readonly clues: string[] = [];
}

readonly prevents replacing the property with another array, though items can still be added to the existing array.

Validate before adding data

function addCriminal(list: Criminal[], criminal: Criminal): void {
  if (criminal.name.trim() === "") {
    throw new Error("A criminal must have a name.");
  }

  list.push(criminal);
}

Transform arrays without mutating the original

const names: string[] = criminals.map((criminal) => criminal.name);
const guiltyCandidates: Criminal[] = criminals.filter(
  (criminal) => criminal.motive !== "None"
);

Using explicit array types at boundaries—such as function parameters, returned API data, and state—helps TypeScript catch incorrect values early.

Common Mistakes

Using an element type instead of an array type

const criminals: Criminal = [];

This is incorrect because criminals is declared as one Criminal, but [] is an array.

const criminals: Criminal[] = [];

Treating a type as a runtime value

const criminals = Criminal[];

This is invalid. Criminal[] describes a type and cannot create an array. Use an array literal:

const criminals: Criminal[] = [];

Omitting the type when the empty array needs a known element type

const criminals = [];

The inferred type for an empty array can be too broad or depend on compiler settings and later usage. Add an annotation when the intended element type is known:

const criminals: Criminal[] = [];

Confusing new Array<Criminal>(3) with three Criminal objects

const criminals = new Array<Criminal>(3);

This creates an array with three empty slots, not three Criminal values. Do not read those slots as valid objects.

If you need three actual objects, create each one:

const criminals: Criminal[] = Array.from({ length: 3 }, (_, index) => ({
  name: `Suspect ${index + 1}`,
  motive: "Unknown"
}));

Using any[] to silence errors

const criminals: any[] = [];

This allows invalid items and removes useful checking. Prefer Criminal[] unless values genuinely have no known shape.

Comparisons

SyntaxMeaningWhen to use it
CriminalOne criminal objectA variable holds exactly one object
Criminal[]An array of criminal objectsThe usual array syntax
Array<Criminal>An array of criminal objectsEquivalent generic syntax; useful for complex types
[]An empty array valueRuntime initialization
new Array<Criminal>(n)Array with n empty slotsRarely appropriate; it does not create objects
`Array<Criminalundefined>`Array whose positions may be empty

For nested arrays, generic syntax can sometimes be easier to read:

const groups: Array<Criminal[]> = [];

This means an array where every item is itself an array of Criminal objects.

Take Quiz

Cheat Sheet

// Empty typed array
const items: Criminal[] = [];

// Equivalent generic syntax
const items: Array<Criminal> = [];

// Add a valid item
items.push({ name: "Alex", motive: "Money" });

// Function parameter and return type
function copy(items: Criminal[]): Criminal[] {
  return [...items];
}

// Create actual values with a factory
const items: Criminal[] = Array.from({ length: 3 }, (_, i) => ({
  name: `Suspect ${i + 1}`,
  motive: "Unknown"
}));

// Slots that may be unfilled
const slots: Array<Criminal | undefined> = Array(3).fill(undefined);

Rules:

  • T means one value of type T.
  • T[] means an array containing T values.
  • A type goes after :; a runtime array is created with [].
  • new Array<T>(length) does not create T objects.

FAQ

How do I declare an empty array of objects in TypeScript?

Use an array type annotation and an empty array literal:

const criminals: Criminal[] = [];

Is Criminal[] the same as Array<Criminal>?

Yes. Both describe an array whose elements are Criminal. Criminal[] is usually more concise.

Why does const item: Criminal = [] fail?

Criminal describes one object, while [] is an array. Use Criminal[] for an array.

Can I use var instead of const?

You can, but const is usually preferred when the variable should always refer to the same array. You can still call push on a const array.

How do I preallocate an array in TypeScript?

For a fixed number of real initial values, use Array.from with a factory function. Avoid new Array<T>(n) unless you specifically want empty slots.

Can an empty Criminal[] contain undefined?

Not by its declared type. If unfilled slots are allowed, declare Array<Criminal | undefined>.

Does TypeScript enforce the array type at runtime?

No. TypeScript checks types during development and compilation. Validate untrusted runtime data, such as API responses, before relying on it.

Take Quiz

Mini Project

Description

Create a small suspect roster for a crime-solving game. The roster begins as an empty typed array, accepts valid suspect objects, and produces a filtered list of suspects who have a known motive.

Goal

Build and use a Criminal[] array without allowing incorrectly shaped objects.

Requirements

  1. Define a Criminal interface with name and motive properties.
  2. Create an empty array typed as Criminal[].
  3. Add at least three valid criminals to the array.
  4. Filter the array to find criminals whose motive is not "Unknown".
  5. Print each matching suspect's name and motive.
Take Quiz

Keep learning

Related questions

View more