0Pricing
TypeScript Academy · Урок

Связи и объединения с типами

Моделируйте связи так, чтобы результаты объединения имели правильные типы

«Связи и объединения с типами» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Преобразование схемы в тип
  2. Типобезопасное построение запросов
  3. Вывод структуры результата запроса
  4. Связи и объединения с типами
← Назад к TypeScript Academy