Подтвердить "любой" объект против интерфейса в TypeScript во время выполнения

Я работаю над пользовательским интерфейсом приложения, используя typescript. В то же время другие работают над предоставлением мне данных. Мы договорились о контракте с данными, однако процесс подвержен ошибкам, и я продолжаю получать недопустимые объекты данных с сервера. Итак, мой вопрос: могу ли я как-то проверить динамические объекты (во время выполнения) с использованием некоторых из моих интерфейсов, определенных в typescript?


<суб > Этот вопрос был задан в 2012 году, поэтому он не может быть дубликат Проверить, реализует ли объект интерфейс во время выполнения с TypeScript в 2015 году.

Ответ 1

Как бы то ни было, интерфейсы TypeScript являются чисто компиляционными объектами времени, поэтому нет возможности выполнять какую-либо проверку времени выполнения, не говоря уже о том, какие интерфейсы существуют во время компиляции. Таким образом, ответ, казалось бы, был бы одним из:

  • Напишите инструмент для преобразования интерфейсов TypeScript к некоторому представлению объекта среды выполнения, которое вы можете использовать для проверки своих объектов, или:
  • Дублируйте свои интерфейсы TypeScript как некоторое представление объекта времени выполнения

Вы можете использовать JSON-схему в качестве представления во время выполнения, так как в Github существует множество валидаторов. Интерфейс TypeScript → Конвертер JSON Schema - это то, что я надеюсь, что кто-то сделает в какой-то момент, но, насколько я знаю, пока не существует.

Ответ 2

Как указывает Брайан, интерфейсы проявляются только во время компиляции и используются компилятором в качестве так называемых именованных типов. Раздел 7 спецификации языка описывает это следующим образом:

Интерфейсы не имеют представления во время выполнения - они являются просто конструкцией во время компиляции. Интерфейсы особенно полезны для документирования и проверки требуемой формы свойств, объектов, передаваемых в качестве параметров, и объектов, возвращаемых из функций.

Далее в разделе 7.4 спецификации есть хорошее описание динамических проверок типов в Typescript:

TypeScript не предоставляет прямого механизма для динамического тестирования того, реализует ли объект конкретный интерфейс. Вместо этого код TypeScript может использовать технику JavaScript для проверки наличия соответствующего набора элементов в объекте...

Пример в спецификации определяет три интерфейса:

interface Mover {
    move(): void;
    getStatus(): {speed: number;};
}

interface Shaker {
    shake(): void;
    getStatus(): {frequency: number;};
}

interface MoverShaker extends Mover, Shaker {
    getStatus(): { speed: number; frequency: number; }; 
}

MoverShaker объединяет Mover и Shaker в новый составной интерфейс. Чтобы проверить во время выполнения, что данный тип соответствует интерфейсу MoverShaker, вы можете использовать код Javascript следующим образом:

var obj: any = getSomeObject();
if (obj && obj.move && obj.shake && obj.getStatus) {
    var moverShaker = <MoverShaker> obj;
    ...
}

Для проверки во время компиляции в Typescript необходимо определить интерфейсы для типов, которыми обмениваются две части вашего приложения. В настоящее время вы должны написать динамический проверочный код (как указано выше) вручную. Следовательно, статический тип и код динамической проверки могут в какой-то момент отличаться, если вы забудете обновить их синхронно. Как отмечает Брайан, было бы неплохо иметь инструмент, который генерирует код автоматически.

Ответ 3

Попробуйте мой динамический интерфейс, если хотите, вот пример (полный пример):

interface PhysicalObject { color : Color; intact : bool; weight : number; }

class Car implements PhysicalObject {
    public intact = true;
    constructor(public color : Color, public weight : number) {};
}

function scratch(aCar : Car) {
    typeCheck(JSVenv, arguments, schemas, ["PhysicalObject"]);
    console.log("Scratching the car!");
    aCar.intact = false;
}

Когда вызывается код, эквивалентный scratch({ intact: 42, color: Color.RED }), выдается такая ошибка:

AssertionError: Runtime typecheck failed on argument number 1:
    Value: { color: 0, weight: 'four', intact: true },
    Schema: ...,
    Error reports (length 1):
    [
      {
        uri: 'urn:uuid:b9b8e6fd-b14b-490d-9372-d2bd22e8a246#/weight',
        schemaUri: 'urn:uuid:c76ddd92-15da-43a6-831e-6717f253efe5#/properties/weight',
        attribute: 'type',
        message: 'Instance is not a required type',
        details: [ 'number' ]
      }
    ]

Инструкции см. на главной странице: https://github.com/ysangkok/typescript-interface-to-jsonschema

Я бы добавил автоматическую проверку типов, но мне нужно что-то вроде node-falafel для TypeScript.