TypeScript - Проверьте, реализует ли класс интерфейс

Я использую интерфейс в Typescript для определения функции, доступной только для некоторых классов, расширяющих базовый класс. Это упрощенная версия кода, который у меня есть до сих пор:

class Animal {
}

interface IWalkingAnimal {
    walk(): void;
}

class Dog extends Animal implements IWalkingAnimal {
}

class Cat extends Animal implements IWalkingAnimal {
}

class Snake extends Animal {
}

private moveAnimal(animal: Animal) {
    if (animal instanceof Cat || animal instanceof Dog) {
        animal.walk();
    }
}

Теперь проблема заключается в том, что я добавлю больше "ходячих" животных, поэтому функция moveAnimal будет слишком большой, чтобы быть управляемой. Я хотел бы сделать следующее:

private moveAnimal(animal: Animal) {
    if (animal implements IWalkingAnimal ) {
        animal.walk();
    }
}

Однако проверка "реализует" не работает, и я не могу найти эквивалент "instanceof" при использовании интерфейсов. В Java кажется, что использование 'instanceof' будет работать здесь, но Typescript не позволит этого.

Существует ли такая вещь в TypeScript, или здесь есть лучший подход? Я использую Typescript 1.8.9.

Ответ 1

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

Вы можете сделать IWalkingAnimal подкласс Animal (и использовать instanceof), или вы можете проверить, имеет ли этот объект метод walk:

if (animal['walk']) {}

Вы можете обернуть это в определяемый пользователем тип защиты (так что компилятор может сузить тип при использовании в инструкции if как с instanceof).

/**
* User Defined Type Guard!
*/
function canWalk(arg: Animal): arg is IWalkingAnimal {
   return (arg as IWalkingAnimal).walk !== undefined;
}


private moveAnimal(animal: Animal) {
    if (canWalk(animal)) {
        animal.walk();  // compiler knows it can walk now
    }
}