webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
TypeScript · Урок 2 из 6

Объекты: type и interface

Форма объектов, необязательные и readonly-поля, Record, type или interface.

Обновлено

Что значит типизировать объект

Вы описываете форму объекта: какие у него ключи и какого типа каждое значение. Затем TS проверяет, что каждый используемый объект соответствует этой форме.

type Product = {
  id: number
  name: string
  price: number
  tags?: string[]          // необязательное — может отсутствовать
  readonly sku: string     // нельзя изменить после создания
}

const p: Product = { id: 1, name: 'Laptop', price: 4000, sku: 'LP-1' }
p.sku = 'X'                // ✗ readonly
p.color                    // ✗ нет в Product

type или interface — различия и когда

Оба описывают форму объекта. В 90% случаев они взаимозаменяемы.

type interface
Объекты ✓ ✓
Union, кортежи, примитивы, функции ('a' | 'b') ✓ ✗
Расширение type B = A & { x: number } interface B extends A { x: number }
Declaration merging (два объявления с одним именем объединяются) ✗ ✓
Сообщения об ошибках иногда длиннее иногда понятнее

Практическая рекомендация: type по умолчанию (подходит для всего), interface — когда пишете библиотеку, которую будут расширять, или когда так принято в команде. Главное — единообразие.

Необязательные и readonly-свойства

type User = {
  id: number
  email: string
  nickname?: string            // string | undefined
  readonly createdAt: Date
}

function displayName(user: User) {
  return user.nickname ?? user.email   // TS заставляет обработать отсутствие
}

Словари: index signature и Record

Когда ключи заранее неизвестны:

type Prices = { [productId: string]: number }
type Prices2 = Record<string, number>            // то же самое, читается лучше

const stock: Record<'ru' | 'kz', number> = { ru: 10, kz: 2 }   // фиксированные ключи из union

Вложенные и составные типы

type Address = { city: string; zip: string }
type Customer = { name: string; address: Address }

type Timestamps = { createdAt: Date; updatedAt: Date }
type Post = { title: string } & Timestamps      // пересечение: есть всё из обоих

Структурная типизация

TS сравнивает объекты по форме, а не по имени: принимается любой объект с нужными полями.

type Point = { x: number; y: number }
const p3 = { x: 1, y: 2, z: 3 }
const p: Point = p3          // ✓ есть x и y — лишнее поле не мешает

(Исключение: литерал объекта, написанный прямо с лишними полями, даёт ошибку — «excess property check», — чтобы ловить опечатки.)

Коротко

  • Типизируете форму объекта; ? — необязательное, readonly — неизменяемое.
  • type по умолчанию; interface — для расширения / библиотек.
  • Record<K, V> для словарей; & для объединения.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.