Owl
Owl

Reputation: 6853

Narrow down type based on class property (from .filter, .find, etc.)

I want to narrow down type based on the class property when calling array .filter or .find

class Square {
    type: "square";

    constructor() {
        this.type = "square";
    }
}

class Circle {
    type: "circle";

    constructor() {
        this.type = "circle";
    }
}

const objects = [
    new Circle(),
    new Square(),
    new Circle(),
    new Square(),
];

// I want `circles` to be Circle[], not (Circle | Square)[]
const circles = objects.filter(o => o.type === "circle");

// I want `square` to be Square | undefined, not Circle | Square | undefined
const square = objects.find(o => o.type === "square");

Is this possible in TypeScript?

TS Playground

Upvotes: 2

Views: 373

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074335

You can do this with type guard functions. Here's an example with the type guard functions defined ahead of time:

function isSquare(obj: {type: string}): obj is Square {
    return obj.type === "square";
}

function isCircle(obj: {type: string}): obj is Circle {
    return obj.type === "circle";
}

// ...

// I want circles to be Circle[]
const circles = objects.filter(isCircle);

// I want square to be Square | undefined
const square = objects.find(isSquare);

Playground link

...but they can also be inline:

// I want circles to be Circle[]
const circles = objects.filter((obj): obj is Circle => obj.type === "circle");

// I want square to be Square | undefined
const square = objects.find((obj): obj is Square => obj.type === "square");

Playground link

Upvotes: 4

Related Questions