Подтвердить "любой" объект против интерфейса в 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.