Avatar ·

Как исключить свойство из типа в TypeScript?

Всем привет! Я начал изучать TypeScript и столкнулся с проблемой, которую не могу решить сам. У меня есть интерфейс для пользователя: ```typescript interface User { id: number; name: string; email: string; password: string; createdAt: Date; } ``` Мне нужно создать новый тип, который будет представлять пользователя без поля `password`, например, для отображения в UI или передачи на клиент. Я не хочу дублировать весь интерфейс, удаляя одно поле вручную, так как это нарушает принцип DRY и усложняет поддержку. Я слышал про встроенные утилиты TypeScript, такие как `Pick`, `Partial`, `Omit`, но не уверен, какая из них подходит для моей задачи. Пробовал использовать `Pick`: ```typescript type UserWithoutPassword = Pick; ``` Это работает, но если у интерфейса будет 20 полей, то перечислять все, кроме одного, неудобно. Возможно, есть способ "исключить" свойство, не перечисляя остальные? Подскажите, как правильно это сделать, и объясните, почему ваш подход лучше. Заранее спасибо! <<>>

Используйте утилиту Omit — это то, что вам нужно

В TypeScript есть встроенная утилита Omit<T, K>, которая создаёт новый тип, исключая из исходного типа T свойства, перечисленные в K. Это идеальное решение для вашей задачи, так как вам не нужно перечислять все оставшиеся поля — достаточно указать только то, что нужно исключить.

// Исходный интерфейс
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// Новый тип без password
type UserWithoutPassword = Omit<User, 'password'>;

// Пример использования
const user: UserWithoutPassword = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com',
  createdAt: new Date(),
  // password: 'secret' // Ошибка! Это свойство исключено
};

Как это работает под капотом

Утилита Omit использует комбинацию других встроенных утилит: Pick и Exclude. Её реализация выглядит так:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
  • keyof T — получает объединение всех ключей типа T (например, 'id' | 'name' | 'email' | 'password' | 'createdAt').
  • Exclude<...> — исключает из этого объединения указанные ключи (например, 'password').
  • Pick<T, ...> — выбирает из T только те свойства, которые остались после исключения.

Преимущества использования Omit

  • DRY-подход: вы не дублируете поля интерфейса.
  • Гибкость: можно исключить несколько свойств сразу: Omit<User, 'password' | 'createdAt'>.
  • Безопасность типов: TypeScript проверит, что исключаемое свойство действительно существует в исходном типе.

Другие полезные приёмы

Если вам нужно исключить свойство по условию (например, все свойства определённого типа), можно написать свой собственный тип:

// Исключить все строковые свойства
type WithoutStringProps<T> = {
  [K in keyof T as T[K] extends string ? never : K]: T[K];
};

type UserWithoutStrings = WithoutStringProps<User>;
// Результат: { id: number; createdAt: Date }

Но для вашей задачи Omit — самый простой и правильный вариант.

<<>>

Альтернатива: используйте Pick с явным перечислением

Хотя Omit удобнее, иногда Pick может быть предпочтительнее, если вы хотите явно указать, какие поля оставить, а не исключать. Например, если интерфейс может измениться в будущем, и вы хотите гарантировать, что новый тип содержит только определённые поля, даже если в исходном интерфейсе появятся новые.

type UserPublic = Pick<User, 'id' | 'name' | 'email'>;

Когда использовать Pick вместо Omit

  • Когда вы хотите защититься от добавления новых полей в исходном типе (они автоматически не попадут в новый тип).
  • Когда нужно оставить только небольшое подмножество полей (например, 3 из 20).
  • Для лучшей читаемости: явно видно, какие поля доступны.

Комбинированный подход

Вы также можете создать свой тип-утилиту, который исключает несколько свойств, но при этом явно указывает оставшиеся:

type ExcludeAndPick<T, Excluded extends keyof T, Picked extends keyof T> = Pick<T, Picked> & Omit<T, Excluded>;
// Но это избыточно — проще использовать Omit или Pick по отдельности.

В большинстве случаев Omit — это то, что вы ищете. Но помните о Pick как о полезной альтернативе для конкретных сценариев.