Связи и объединения с типами
Моделируйте связи так, чтобы результаты объединения имели правильные типы
«Связи и объединения с типами» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.
Типизированные связи и вложенные результаты
В настоящих схемах есть связи: у пользователя есть много записей, а запись принадлежит пользователю. Типобезопасный ORM позволяет объявить эти связи и затем возвращает корректно вложенные типизированные результаты реляционных запросов.
Объявление связей
Наряду с таблицами Вы определяете объект связей, описывающий их соединение. Эти метаданные используются и для генерации SQL, и для определения типа результата.
import { relations } from "drizzle-orm";
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));Реляционный запрос
API запросов позволяет запросить связанные строки с помощью with. Результат вкладывает связанные данные под именем связи.
const result = await db.query.users.findMany({
with: { posts: true },
});
// result: (User & { posts: Post[] })[]one и many определяют структуру типа
Связь many возвращает массив, а связь one — один объект или null. Вложенный тип соответствует объявленной кратности.
const r = await db.query.posts.findMany({
with: { author: true },
});
// r: (Post & { author: User })[] // author is a single objectВыбор столбцов внутри связей
Вы можете сузить и родительские строки, и вложенные строки. Тип результата независимо сужается на каждом уровне.
const r = await db.query.users.findMany({
columns: { id: true, name: true },
with: {
posts: { columns: { title: true } },
},
});
// r: { id: number; name: string; posts: { title: string }[] }[]Ручные соединения с типизированными столбцами
Соединения на более низком уровне также сохраняют типизацию. Предикат соединения использует типизированные ссылки на столбцы, а select определяет плоскую структуру результата.
const rows = await db
.select({ author: users.name, title: posts.title })
.from(posts)
.innerJoin(users, eq(users.id, posts.authorId));
// rows: { author: string; title: string }[]left join добавляет допустимость NULL
Операция LEFT JOIN может вернуть отсутствующие строки с правой стороны, поэтому присоединённые столбцы становятся допускающими NULL в типе результата. ORM автоматически отражает это.
const rows = await db
.select({ name: users.name, title: posts.title })
.from(users)
.leftJoin(posts, eq(posts.authorId, users.id));
// rows: { name: string; title: string | null }[]Вложенные и плоские результаты
Реляционные запросы (findMany + with) возвращают вложенные объекты, а ручные соединения — плоские строки. Выбирайте вложенные результаты для объектных графов, а плоские — для табличных проекций.
Как типизируется вложенность
Метаданные связей считываются на уровне типов. Тип запроса пересекает базовую строку с объектом, ключами которого являются запрошенные связи, а значением каждой связи — массив или одиночный тип в соответствии с её кратностью.
type WithPosts = User & { posts: Post[] };
// "many" -> Post[], "one" -> User (or User | null for optional)Глубоко вложенные связи
Связи можно комбинировать. Вы можете запросить связь другой связи, и тип будет вложен на такую же глубину — всё выводится автоматически.
await db.query.users.findMany({
with: { posts: { with: { comments: true } } },
});
// User & { posts: (Post & { comments: Comment[] })[] }Почему это важно
Ручная типизация результатов вложенных соединений подвержена ошибкам и постепенно расходится со схемой. Выведение их из объявленных связей синхронизирует тип объектного графа с SQL, поэтому переименование связи становится ошибкой компиляции, а не неожиданностью в рабочей среде.
Быстрая проверка
Проверьте, насколько хорошо Вы поняли типизированные связи и соединения.
Итоги
Вы объявили связи, а затем позволили ORM создавать вложенные типизированные результаты: many даёт массивы, one — одиночные объекты, частичные выборки сужают каждый уровень, операции LEFT JOIN добавляют допустимость NULL, а глубоко вложенные связи комбинируются. Метаданные связей управляют и SQL, и типами результатов, поддерживая их синхронность.
Часто задаваемые вопросы
Урок «Связи и объединения с типами» бесплатный?
Да — полный текст урока «Связи и объединения с типами» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.
Чему я научусь в уроке «Связи и объединения с типами»?
Моделируйте связи так, чтобы результаты объединения имели правильные типы Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Связи и объединения с типами»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Преобразование схемы в тип
- Типобезопасное построение запросов
- Вывод структуры результата запроса
- Связи и объединения с типами