Is there a way to put multiple types of data in an array in TypeScript?

5.7k views Asked by At

Here's an example of what I'm asking.
Say that we have two interfaces, Cats and Dogs. How can I make an array that can hold both Cats and Dogs?

interface Cats {
  name: string;
  age: number;
}

interface Dog {
  owner: string;
}

const cat1: Cats = {
  name: "Jimmy",
  age: 5,
}

const dog1: Dogs = {
  owner: "Bobby",
}

// The line below doesn't work how I think it would work
const animalsList: Array<Cats> | Array<Dogs> = [cat1, dog1];

The variable animalsList should be able to have both Cats and Dogs in it, but I am getting errors like
"Type Dogs can not be assigned to type Array<Cats>"

2

There are 2 answers

0
Fernando Gonzalez Sanchez On BEST ANSWER

Here is a full sample:

// Welcome to the TypeScript Playground, this is a website
// which gives you a chance to write, share and learn TypeScript.

// You could think of it in three ways:
//
//  - A place to learn TypeScript in a place where nothing can break
//  - A place to experiment with TypeScript syntax, and share the URLs with others
//  - A sandbox to experiment with different compiler features of TypeScript

const anExampleVariable = "Hello World"
console.log(anExampleVariable)

// To learn more about the language, click above in "Examples" or "What's New".
// Otherwise, get started by removing these comments and the world is your playground.
  
class Cats {
    private name: String;
    constructor(name: String) {
        this.name = name;
    }
    public dump() { console.log(`I am cat ${this.name}`); }
}
class Dogs {
    private name: String;
    constructor(name: String) {
        this.name = name;
    }
    public dump() { console.log(`I am dog ${this.name}`); }
}

class Test {
    public animalsList : Array<Cats> | Array<Dogs> = Array();
}

const t = new Test();
t.animalsList = Array(new Cats('cat1'), new Cats('cat2'));
t.animalsList.forEach((v, i) => { v.dump(); });

t.animalsList = Array(new Dogs('pluto'), new Dogs('goofy'));
t.animalsList.forEach((v, i) => { v.dump(); });

// The following line fails
//t.animalsList = Array(new Dogs('pluto'), new Cats('cat2'));
//t.animalsList.forEach((v, i) => { v.dump(); });

You can try it on https://www.typescriptlang.org/play

2
Samathingamajig On

If I am reading this question correctly, you want to be able to make an Array that can hold both Cats and Dogs. The way it is currently Array<Cats> | Array<Dogs> means that you can have either a) an array that can hold ONLY Cats, or b) an array that can hold ONLY Dogs.

To fix this, you need to have an array that can hold both. The way to do that is below:

public animalsList: Array<Cats | Dogs>;

The new location of the pipe (|) tells that this Array is an array that can hold both Cats and Dogs at the same time.

Another option, mentioned by @cherryblossom, is this:

public animalsList: (Cats | Dogs)[];

Which works a similar way