Typescript сужает тип на основе свойства класса (из .filter, .find и т. Д.)

#typescript

#typescript

Вопрос:

Я хочу сузить тип на основе свойства класса при вызове array .filter или .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");
 

Возможно ли это в Typescript?

Игровая площадка TS

Комментарии:

1. Какую ES-версию вы должны использовать? какие-либо ограничения или будет ли работать ES2019? (Я спрашиваю, потому что для игровой площадки установлено значение ES2017).

2. objects.filter((o): o is Circle => o.type === "circle");

Ответ №1:

Вы можете сделать это с помощью функций защиты типов. Вот пример с функциями защиты типов, определенными заранее:

 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);
 

Ссылка на игровую площадку

… но они также могут быть встроенными:

 // 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");
 

Ссылка на игровую площадку

Комментарии:

1. Это работает, спасибо. Таким образом, typescript не может автоматически определять тип на основе значения свойства? Поскольку тип type свойства является статической строкой (нет string ) Я думал, что Typescript сможет обнаружить его автоматически.

2.@Owl — я был немного удивлен, что создание type readonly не позволило сделать правильный вывод, но существуют ограничения на то, что делает компилятор TypeScript, из-за того, сколько времени потребуется для этого (а не только может ли он это сделать). Тем не менее, я был удивлен. Я не могу с уверенностью сказать, что другого способа нет (TypeScript чрезвычайно сложен), но функции защиты типов работают. 🙂