Joi предоставляет механизм работы с составными схемами, где одна из
ключевых возможностей — извлечение части схемы по пути. Метод
extract применяется к уже собранной схеме и позволяет
получить под-схему, соответствующую конкретному пути в объектной
структуре.
Метод вызывается на экземпляре схемы:
const subSchema = schema.extract(path);
path — строка, описывающая путь к вложенному полю, либо
массив ключей.
Пример:
const schema = Joi.object({
user: Joi.object({
name: Joi.string(),
age: Joi.number(),
}),
meta: Joi.object({
createdAt: Joi.date(),
})
});
const nameSchema = schema.extract('user.name');
Результат — схема Joi.string(), извлечённая из глубоко
вложенной структуры.
extract интерпретирует путь как последовательность
ключей:
user → объектuser.name → строковая схемаmeta.createdAt → схема датыЭто не копирование структуры, а получение ссылки на часть схемы, уже описанной в исходной конфигурации.
Поведение зависит от структуры исходной схемы:
Joi.object().pattern()) могут не
поддерживать прямой extractПример ошибки:
schema.extract('user.address.city'); // если address не определён
extract часто применяется для:
Пример:
const baseUserSchema = Joi.object({
id: Joi.string(),
profile: Joi.object({
name: Joi.string(),
email: Joi.string(),
})
});
const emailSchema = baseUserSchema.extract('profile.email');
extract от
reachВ экосистеме Joi также встречается метод reach, и важно
различать их поведение:
extract — работает на экземпляре
схемыreach — работает на корневом объекте
Joiconst Joi = require('joi');
const schema = Joi.object({
a: Joi.object({
b: Joi.string()
})
});
const sub = schema.extract('a.b');
// vs
const sub2 = Joi.reach(schema, 'a.b');
Ключевое различие — контекст вызова и сценарий использования в библиотеке.
В типовой системе Joi важную роль играют вспомогательные типы, позволяющие синхронизировать runtime-схемы и compile-time типы.
Типы выводятся из схемы через условные и выводимые конструкции:
Joi.Schema как базовый типЧасто используется паттерн:
type User = Joi.extractType<typeof schema>;
или эквивалентные формы в зависимости от версии типизации.
Суть механизма:
Joi.object()const schema = Joi.object({
id: Joi.string(),
age: Joi.number(),
isActive: Joi.boolean()
});
Результирующий тип:
type User = {
id: string;
age: number;
isActive: boolean;
}
При использовании .optional() или
.default() типы автоматически становятся расширенными:
const schema = Joi.object({
id: Joi.string(),
nickname: Joi.string().optional()
});
Тип:
type Result = {
id: string;
nickname?: string;
}
Для вложенных объектов применяется рекурсивная модель:
const schema = Joi.object({
user: Joi.object({
profile: Joi.object({
email: Joi.string()
})
})
});
Тип:
type Email = string;
или:
type UserProfile = {
user: {
profile: {
email: string;
}
}
}
extract и типовой системыСильная сторона Joi заключается в том, что runtime-операции и типизация могут использовать одинаковую структуру.
Пример сценария:
const schema = Joi.object({
user: Joi.object({
name: Joi.string(),
email: Joi.string()
})
});
const emailSchema = schema.extract('user.email');
Типовая модель может быть синхронизирована:
type Email = string;
При работе с многоуровневыми схемами важно учитывать:
.alter(), .when() могут менять
структуру динамическиСхемы делятся на доменные части:
Каждая часть может быть извлечена независимо:
const authSchema = schema.extract('auth.login');
Базовая схема служит источником атомарных правил:
При изменении структуры API можно извлекать только нужные части без переписывания всей схемы.
Типовая система Joi имеет ряд особенностей:
.when() могут теряться в inferenceЕсли схема изменяется динамически:
Joi.object().keys(dynamicConfig)
типовая система может не отразить реальную структуру, и
extract остаётся только runtime-инструментом.
extract — механизм навигации по схемам