Quartet 9: Allegro | Краткость и простота

от автора

Когда я создавал библиотеку для валидации данных quartet, взял следующие цели-ориентиры:

В этой статье покажу как библиотека quartet понимает, что значат слова "Краткий" и "Простой" в контексте подхода к валидации.

Как работает quartet?

Когда он нужен? Он нужен тогда, когда нужна валидация данных
Что такое валидация? Проверка данных на соответствия требованиям. Чаще всего типам.
Как quartet в этом помогает? Он создает функцию валидации на основании декларативного описания требований — схемы. Функция-компилятор v преобразует схемы в функции валидации. Также внутри v хранятся заготовленные схемы и методы для создания более сложных схем. Детальнее смотрите в документации.

Как это работает?

  1. Пишешь схему
  2. Даешь ее на вход функции-компилятору v чтобы получить функцию валидации.
  3. Функция валидаци готова к использованию!

Давайте с помощью quartet отвалидируем все данные не напрягая мозг в семь подходов.

Начнём с легкого и постепенно будем увеличивать сложность требований.

Валидация типа с единственным примитивным значением

Например:

type Answer = 42;

Схема этого типа в quartet:

const answerSchema = 42;

Чтобы получить его функцию-валидатор пишем код:

import { v } from "quartet"; const checkAnswer = v(42);

Всё просто. Схема примитива — он сам.

Валидация встроенных типов

Предположим мы хотим валидировать не конкретную строку, а все строки. Или не одно конкретное число — а все числа.

Напишем пару валидаторов для примитивных типов. Посмотрим, что в них общее, а что нет.

const checkNumber = (x) => typeof x === "number"; const checkString = (x) => typeof x === "string"; const checkBoolean = (x) => typeof x === "boolean"; const checkSymbol = (x) => typeof x === "symbol"; // ...

У них одна структура:

const checkSomeType = x => typeof x === "<type>", где <type> – нужный нам тип

Итого для каждого примитивного типа, у нас есть схема:

Тип Схема
'string' v.string
'number' v.number
'boolean' v.boolean
'symbol' v.symbol

Итак, мы можем получить функцию валидации числа таким образом:

const checkNumber = v(v.number); // то же, что const checkNumber = (x) => typeof x === "number";

Функции в quartet валидируются таким же способом

Тип Схема
'function' v.function

На практике это выглядит так:

const checkFunction = v(v.function); // то же, что const checkFunction = (x) => typeof x === "function";

Всё просто. Cхема типа — одноименный метод с префиксом v..

Операция «Или» для схем

Предположим у нас есть такой тип:

type NullableString = string | null;

Схема этого типа в quartet:

const nullableStringSchema = [v.string, null];

А функция валидации получим написав так:

const checkNullableString = v([v.string, null]);

В общем виде можно представить в виде типа:

type VariantSchema = Schema[];

Всё просто. Схема валидации вариантов – массив схем.

Операция «И» для схем

Допустим у нас есть объект у которого

type Password =  string // Пароль должен быть длиннее 8-ми символов и содержать как минимум 1 букву и цифру.

Опишем эти требования с помощью схем. Для такого случая есть методы v.minLength() и v.test(RegExp)

const stringSchema = v.string; const min8Schema = v.minLength(8); const atLeastOneDigitSchema = v.test(/\d/); const atLeastOneLetterSchema = v.test(/[A-Za-z]/);

Чтобы объединить схемы у нас есть метод v.and():

const passwordSchema = v.and(     stringSchema,     min8Schema,     atLeastOneDigitSchema,     atLeastOneLetterSchema, )

Всё просто. Для нескольких проверок используй v.and(схема, схема, ...).

Валидация интерфейсов

Предположим есть интерфейс объекта Person:

interface Person {     name: string     age: number }

Что нужно знать, чтобы выполнить проверку обьекта на соответствие интерфейсу Person?
Необходимо знать, что у него есть поля с именами name и age. И они должны быть типа string и number. И больше ничего!

Таким образом нам нужно иметь возможность перечислить, какие у объекта должны быть поля, и какие схемы им соответствуют.

Наиболее подходящей для этого структурой данных является — объект!

Итак схема выглядит так:

const personSchema = {   name: v.string,   age: v.number, };

В общем виде схему интерфейса можно представить так:

interface ObjectInterfaceSchema {   [propertyName: string]: Schema; }

Всё просто. Схема валидации интерфейса объекта — объект, в котором ключи — это поля объекта, а значения — схемы валидации.

Валидация масивов

Допустим у нас масив чисел:

type Numbers = number[];

Для этого у нас есть метод v.arrayOf(). На вход метода идёт схема елемента.

const checkNumbers = v(v.arrayOf(v.number));

Всё просто. Для валидации масива используй v.arrayOf(схема елемента).

Пользовательская валидация

А что если мы хотим встроить свою валидацию в схему quartet.

Давайте создадим схему проверки на парность числа. Для єтого напишем пользовательскую схему с помощью метода v.custom(своя функция валидации):

const evenSchema = v.custom((x) => x % 2 === 0) const evenNumberSchema = v.and(   v.number,   evenSchema, );

Всё просто. Для своих проверок используй v.custom(своя функция валидации).

Выводы

  • Схема примитива — он сам.
  • Cхема типа — одноименный метод с префиксом v..
  • Схема валидации вариантов — массив схем.
  • Для нескольких проверок используй v.and(схема, схема, ...).
  • Схема валидации интерфейса объекта — объект, в котором ключи — это поля объекта, а начения — схемы валидации.
  • Для валидации масива используй v.arrayOf(схема елемента).
  • Для своих проверок используй v.custom(своя функция валидации).

P.S.

Я работаю в компании. Внедрение библиотеки quartet было так:
Поначалу разработчики подходили и спрашивали как написать проверку того или иного случая. После 4 вопросов они легко пишут валидации, которые им нужны.

Интересно послушать про ваш опыт работы с валидацией данных, напишите в комментариях об этом!

ссылка на оригинал статьи https://habr.com/ru/post/496376/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *