14

I am using Array.filter and instanceof to get all the objects of a certain type out of a more generic array.

 let cars:Car[] = this.gameObjects.filter(go => go instanceof Car)

This works! But the typescript compiler doesn't agree that the returned types are all of the Car type.

Type 'GameObject[]' is not assignable to type 'Car[]'

On the Typescript GitHub this issue is considered solved by adding an interface for array.filter. That doesn't work for me, it still gives the same error. You can try it out by pasting this code in the typescript playground:

interface Array<T> {
    filter<U extends T>(pred: (a: T) => a is U): U[];
}

class Car { 
    drive() { 

    }
}
class GameObject { 

}

let gameObjects:GameObject[] = [new Car(), new Car()]

let cars:Car[] = gameObjects.filter((go) => go instanceof Car)

Am I missing something here? How can I filter an array by type and get back an array of the correct type?

1 Answer 1

15

To change the return type on filter function you must use a Type Guard Function like the following. You also don't need to extend the Array type because that's already defined on TypeScript.

class GameObject { 

}

class Car { 
    drive() { 

    }
}

let isCar = (obj: any): obj is Car => {
    return obj instanceof Car;
}

let gameObjects: GameObject[] = [new Car(), new Car()]

let cars: Car[] = gameObjects.filter(isCar)
1
  • Note, it's also possible to define the type guard inline: gameObjects.filter((obj: any): obj is Car => obj instanceof Car). You can even leave out : any as it's automatically inferred from the gameObjects array.
    – Xerillio
    Commented Jan 2, 2022 at 13:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.