Українська

Дізнайтеся про часткові типи TypeScript — потужну функцію для створення необов'язкових властивостей, що спрощує маніпуляції з об'єктами та покращує підтримку коду.

Опанування часткових типів TypeScript: перетворення властивостей для гнучкості

TypeScript, надмножина JavaScript, привносить статичну типізацію у динамічний світ веброзробки. Однією з його потужних особливостей є тип Partial, який дозволяє створювати тип, де всі властивості існуючого типу є необов'язковими. Ця можливість відкриває безліч гнучких рішень при роботі з даними, маніпуляціях з об'єктами та взаємодії з API. У цій статті ми детально розглянемо тип Partial, наведемо практичні приклади та найкращі практики для його ефективного використання у ваших проєктах на TypeScript.

Що таке частковий тип у TypeScript?

Тип Partial<T> є вбудованим допоміжним типом у TypeScript. Він приймає тип T як свій узагальнений аргумент і повертає новий тип, у якому всі властивості T є необов'язковими. По суті, він перетворює кожну властивість з required (обов'язкової) на optional (необов'язкову), що означає, що вони не обов'язково мають бути присутніми при створенні об'єкта цього типу.

Розглянемо наступний приклад:


interface User {
  id: number;
  name: string;
  email: string;
  country: string;
}

const user: User = {
  id: 123,
  name: "Alice",
  email: "alice@example.com",
  country: "USA",
};

Тепер створимо Partial-версію типу User:


type PartialUser = Partial<User>;

const partialUser: PartialUser = {
  name: "Bob",
};

const anotherPartialUser: PartialUser = {
  id: 456,
  email: "bob@example.com",
};

const emptyUser: PartialUser = {}; // Допустимо

У цьому прикладі PartialUser має властивості id?, name?, email? та country?. Це означає, що ви можете створювати об'єкти типу PartialUser з будь-якою комбінацією цих властивостей, або навіть без них. Присвоєння emptyUser демонструє це, підкреслюючи ключовий аспект Partial: він робить усі властивості необов'язковими.

Навіщо використовувати часткові типи?

Типи Partial є цінними в кількох сценаріях:

Практичні приклади використання часткових типів

1. Оновлення профілю користувача

Уявіть, що у вас є функція, яка оновлює профіль користувача. Ви не хочете вимагати, щоб функція щоразу отримувала всі властивості користувача; натомість ви хочете дозволити оновлення лише конкретних полів.


interface UserProfile {
  firstName: string;
  lastName: string;
  age: number;
  country: string;
  occupation: string;
}

function updateUserProfile(userId: number, updates: Partial<UserProfile>): void {
  // Симуляція оновлення профілю користувача в базі даних
  console.log(`Оновлення користувача ${userId} з даними:`, updates);
}

updateUserProfile(1, { firstName: "David" });
updateUserProfile(2, { lastName: "Smith", age: 35 });
updateUserProfile(3, { country: "Canada", occupation: "Software Engineer" });

У цьому випадку Partial<UserProfile> дозволяє передавати лише ті властивості, які потрібно оновити, не викликаючи помилок типізації.

2. Створення об'єкта запиту для API

При виконанні запитів до API у вас можуть бути необов'язкові параметри. Використання Partial може спростити створення об'єкта запиту.


interface SearchParams {
  query: string;
  category?: string;
  location?: string;
  page?: number;
  pageSize?: number;
}

function searchItems(params: Partial<SearchParams>): void {
  // Симуляція виклику API
  console.log("Пошук з параметрами:", params);
}

searchItems({ query: "laptop" });
searchItems({ query: "phone", category: "electronics" });
searchItems({ query: "book", location: "London", page: 2 });

Тут SearchParams визначає можливі параметри пошуку. Використовуючи Partial<SearchParams>, ви можете створювати об'єкти запитів лише з необхідними параметрами, що робить функцію більш універсальною.

3. Створення об'єкта форми

При роботі з формами, особливо багатокроковими, використання Partial може бути дуже корисним. Ви можете представити дані форми як об'єкт Partial і поступово заповнювати його в міру того, як користувач заповнює форму.


interface AddressForm {
  street: string;
  city: string;
  postalCode: string;
  country: string;
}

let form: Partial<AddressForm> = {};

form.street = "123 Main St";
form.city = "Anytown";
form.postalCode = "12345";
form.country = "USA";

console.log("Дані форми:", form);

Цей підхід корисний, коли форма є складною, і користувач може не заповнювати всі поля одночасно.

Комбінування Partial з іншими допоміжними типами

Partial можна комбінувати з іншими допоміжними типами TypeScript для створення більш складних та індивідуальних перетворень типів. Деякі корисні комбінації включають:

Приклад: Partial з Pick

Припустимо, ви хочете, щоб лише певні властивості User були необов'язковими під час оновлення. Ви можете використати Partial<Pick<User, 'name' | 'email'>>.


interface User {
  id: number;
  name: string;
  email: string;
  country: string;
}


type NameEmailUpdate = Partial<Pick<User, 'name' | 'email'>>;

const update: NameEmailUpdate = {
  name: "Charlie",
  // country тут не дозволено, лише name та email
};

const update2: NameEmailUpdate = {
  email: "charlie@example.com"
};

Найкращі практики при використанні часткових типів

Глобальні аспекти та приклади

При роботі з глобальними додатками важливо враховувати, як типи Partial можна ефективно використовувати в різних регіонах та культурних контекстах.

Приклад: Міжнародні адресні форми

Формати адрес значно відрізняються в різних країнах. Деякі країни вимагають певних компонентів адреси, тоді як інші використовують різні системи поштових індексів. Використання Partial може врахувати ці відмінності.


interface InternationalAddress {
  streetAddress: string;
  apartmentNumber?: string; // Необов'язково в деяких країнах
  city: string;
  region?: string; // Провінція, штат тощо.
  postalCode: string;
  country: string;
  addressFormat?: string; // Для визначення формату відображення залежно від країни
}


function formatAddress(address: InternationalAddress): string {
  let formattedAddress = "";

  switch (address.addressFormat) {
    case "UK":
      formattedAddress = `${address.streetAddress}\n${address.city}\n${address.postalCode}\n${address.country}`;
      break;
    case "USA":
      formattedAddress = `${address.streetAddress}\n${address.city}, ${address.region} ${address.postalCode}\n${address.country}`;
      break;
    case "Japan":
      formattedAddress = `${address.postalCode}\n${address.region}${address.city}\n${address.streetAddress}\n${address.country}`;
      break;
    default:
      formattedAddress = `${address.streetAddress}\n${address.city}\n${address.postalCode}\n${address.country}`;
  }
  return formattedAddress;
}

const ukAddress: Partial<InternationalAddress> = {
  streetAddress: "10 Downing Street",
  city: "London",
  postalCode: "SW1A 2AA",
  country: "United Kingdom",
  addressFormat: "UK"
};

const usaAddress: Partial<InternationalAddress> = {
    streetAddress: "1600 Pennsylvania Avenue NW",
    city: "Washington",
    region: "DC",
    postalCode: "20500",
    country: "USA",
    addressFormat: "USA"
};

console.log("Адреса у Великій Британії:\n", formatAddress(ukAddress as InternationalAddress));
console.log("Адреса у США:\n", formatAddress(usaAddress as InternationalAddress));

Інтерфейс InternationalAddress дозволяє використовувати необов'язкові поля, такі як apartmentNumber та region, для врахування різних форматів адрес у всьому світі. Поле addressFormat можна використовувати для налаштування способу відображення адреси залежно від країни.

Приклад: Налаштування користувача в різних регіонах

Налаштування користувача можуть відрізнятися в різних регіонах. Деякі налаштування можуть бути актуальними лише в певних країнах або культурах.


interface UserPreferences {
  darkMode: boolean;
  language: string;
  currency: string;
  timeZone: string;
  pushNotificationsEnabled: boolean;
  smsNotificationsEnabled?: boolean; // Необов'язково в деяких регіонах
  marketingEmailsEnabled?: boolean;
  regionSpecificPreference?: any; // Гнучке налаштування для конкретного регіону
}

function updateUserPreferences(userId: number, preferences: Partial<UserPreferences>): void {
  // Симуляція оновлення налаштувань користувача в базі даних
  console.log(`Оновлення налаштувань для користувача ${userId}:`, preferences);
}


updateUserPreferences(1, {
    darkMode: true,
    language: "en-US",
    currency: "USD",
    timeZone: "America/Los_Angeles"
});


updateUserPreferences(2, {
  darkMode: false,
  language: "fr-CA",
  currency: "CAD",
  timeZone: "America/Toronto",
  smsNotificationsEnabled: true // Увімкнено в Канаді
});

Інтерфейс UserPreferences використовує необов'язкові властивості, такі як smsNotificationsEnabled та marketingEmailsEnabled, які можуть бути актуальними лише в певних регіонах. Поле regionSpecificPreference надає додаткову гнучкість для додавання налаштувань, специфічних для регіону.

Висновок

Тип Partial у TypeScript — це універсальний інструмент для створення гнучкого та легкого для підтримки коду. Дозволяючи визначати необов'язкові властивості, він спрощує маніпуляції з об'єктами, взаємодію з API та обробку даних. Розуміння того, як ефективно використовувати Partial, а також його комбінації з іншими допоміжними типами, може значно покращити ваш процес розробки на TypeScript. Пам'ятайте про обачливе використання, чітке документування його призначення та перевірку даних, щоб уникнути потенційних проблем. При розробці глобальних додатків враховуйте різноманітні вимоги різних регіонів і культур, щоб використовувати типи Partial для створення адаптивних та зручних для користувача рішень. Опанувавши часткові типи, ви зможете писати більш надійний, адаптивний та легкий у підтримці код на TypeScript, який зможе елегантно та точно обробляти різноманітні сценарії.