predicate typescript
Нашел вот такую доку по predicates и хочу сделать +/- по аналогии https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
Пытаюсь написать свой код:
type CtorType<T extends Animal> = {
new(...args: any[]): T
}
class Animal {
static isAnimal<T extends Animal>(animal: T): animal is T { // animal is T - не работает
const Ctor = (this as any) as CtorType<T> // тут не понятно, без явного as any, даже не компилится ????
return animal instanceof Ctor
}
name: string
constructor(name: string) {
this.name = name
}
}
class Rabbit extends Animal {
constructor() {
super('Rabbit')
}
}
const rabbit: Animal = new Rabbit()
const isRabbit = (animal: Animal): animal is Rabbit => { // animal is Rabbit - не работает
return animal instanceof Rabbit
}
if (Rabbit.isAnimal(rabbit)) {
type MyAnimal1 = typeof rabbit // type MyAnimal = Animal
}
if (isRabbit(rabbit)) {
type MyAnimal2 = typeof rabbit // type MyAnimal = Animal
}
if (rabbit instanceof Rabbit) {
type MyAnimal3 = typeof rabbit // type MyAnimal3 = Rabbit
}
Хочу добавить в базовый класс статичный метод isAnimal, который проверял - порожден ли инстанс от соответствующего класса, чтобы потом внутри блока if, если это так, применял соответствующий тип. Но у меня что-то не выходит. Rabbit.isAnimal(rabbit)
Далее написал еще более простую функцию isRabbit, которая уже явно проверяет - происходит ли инстанс от класса Rabbit. Тут тоже внутри блока if все равно тип Animal, причем если в условии явно написать rabbit instanceof Rabbit, то все ок
Ответы (2 шт):
Typescript иногда (но редко) делает довольно неявные вещи.
В данном случае Rabbit.isAnimal не работает потому что дженерик в isAnimal привязан конкретно к Animal и не зависит от того кто его наследует.
Использование же T extends typeof this не работает в статических методах (увы).
Конструкция animal is Rabbit не будет работать до тех пор пока класс Rabbit не имеет како-либо отличительное свойство/метод от Animal, даже приватный. Пример:
class Rabbit extends Animal {
private legLength = 5 // То самое отличие от Animal
constructor() {
super('Rabbit')
}
}
if (isRabbit(rabbit)) {
type AnimalType = typeof rabbit // AnimalType is Rabbit
}
static isAnimal<T extends Animal>(animal: T): animal is T { // animal is T - не работает
Ну наоборот же:
static isAnimal<T>(animal: T): animal is Animal
if (isRabbit(rabbit)) { type MyAnimal2 = typeof rabbit // type MyAnimal = Animal }
Тайпскрипт использует структурную типизацию, а у тебя классы Rabbit и Animal ничем не отличаются.
Добавь кролику любое отличие от животного и всё заработает:
