Проблема
В последней статье я обсуждал использование runtypes для подключения статических типов и проверки во время выполнения. Теория, лежащая в основе runtypes, состоит в том, что у runtypes есть собственный язык определений, который может преобразовываться в функцию проверки во время выполнения и тип статического машинописного текста. Делая это, мы можем удалить дублирование в двух мирах.
Это здорово, однако один из самых больших минусов этого подхода: runtypes определен хороший язык определений, но он малоизвестен. Из-за этого невозможно создать сильную экосистему для разных сценариев.
Например, недавно я работал над проектом REST API, и мы используем открытый API для создания интерактивного документа. Однако нам приходится писать машинописные типы для этих запросов и ответов, что раздражает и очень легко сделать ошибку. Я предполагаю, что у нас мог бы быть какой-то инструмент, который мог бы генерировать эти типы машинописных текстов на основе открытого документа API, точно так же, как это делает graphql-codegen для схемы GraphQL.
Потому что открытый стандарт API зависит от схемы JSON, хорошо известного стандарта. Если мы сможем подключить статические типы и проверку во время выполнения на основе схемы JSON, я думаю, многие проблемы будут решены.
Другое решение
И это возможно!
Давайте посмотрим на пример файла схемы JSON с именем person.json:
{
“title”: “Person”,
“type”: “object”,
“properties”: {
“firstName”: {
“type”: “string”
},
“lastName”: {
“type”: “string”
},
“age”: {
“description”: “Age in years”,
“type”: “integer”,
“minimum”: 0
},
“hairColor”: {
“enum”: [“black”, “brown”, “blue”],
“type”: “string”
}
},
“additionalProperties”: false,
“required”: [“firstName”, “lastName”]
}
Все, возможно, знают, что уже существует множество валидаторов схемы JSON, например: ajv, которые могут проверять передаваемые данные по заданной схеме JSON. Давайте приведем приведенный выше пример для проверки объекта:
import Ajv, { JSONSchemaType, DefinedError } from "ajv";
const validateObj = (obj: unknown) => {
const ajv = new Ajv();
const validate = ajv.compile({
title: "Example Schema",
type: "object",
properties: {
firstName: {
type: "string"
},
lastName: {
type: "string"
},
age: {
description: "Age in years",
type: "integer",
minimum: 0
},
hairColor: {
enum: ["black", "brown", "blue"],
type: "string"
}
},
additionalProperties: false,
required: ["firstName", "lastName"]
});
if (validate(obj)) {
// data is MyData here
console.log("It is a valid obj: ", JSON.stringify(obj));
} else {
console.log("It is not a valid obj: ", JSON.stringify(obj));
for (const err of validate.errors as DefinedError[]) {
console.log(err);
}
}
};
validateObj({});
validateObj({
firstName: "luke",
lastName: "skywalker",
age: 16,
hairColor: "black"
});
И вывод ниже:
It is not a valid obj: {} {keyword: "required", dataPath: "", schemaPath: "#/required", params: Object, message: "should have required property 'firstName'"} It is a valid obj: {"firstName":"luke","lastName":"skywalker","age":16,"hairColor":"black"}
И есть еще один инструмент под названием json-schema-to-typescript, который может генерировать машинописный текст на основе схемы JSON.
Например, учитывая приведенную выше схему JSON, выполните следующую команду:
yarn add json-schema-to-typescript json2ts person.json > person.d.ts
Он сгенерирует следующий машинописный файл:
export interface Person {
firstName: string;
lastName: string;
/**
* Age in years
*/
age?: number;
hairColor?: "black" | "brown" | "blue";
}
Подвести итог
В этой статье мы используем другой подход для соединения проверки в реальном времени и статического машинописного типа с использованием более стандартной схемы JSON. Проверьте следующую диграмму для более подробной информации:

Первоначально опубликовано на https://github.com.