Пошук уроків, статей та іншого контенту
Навчіться змінювати обов’язковість і доступність властивостей типів за допомогою Partial, Required та Readonly.
У TypeScript властивості типу можуть мати спеціальні модифікатори:
? робить властивість необов’язковою;
readonly забороняє змінювати властивість після створення об’єкта.
interface User {
id: number;
name: string;
email?: string;
}
interface Product {
readonly id: number;
name: string;
}У типі User властивість email необов’язкова, тому її можна не вказувати:
const user: User = {
id: 1,
name: "Олена"
};У типі Product властивість id доступна для читання, але її не можна змінити:
const product: Product = {
id: 10,
name: "Клавіатура"
};
// Помилка TypeScript:
// product.id = 20;TypeScript надає готові utility types для зміни цих властивостей у вже наявних типах:
Partial<Type>;
Required<Type>;
Readonly<Type>.
Partial<Type> робить всі властивості типу необов’язковими.
Наприклад, маємо тип користувача:
interface User {
id: number;
name: string;
email: string;
}Без Partial об’єкт повинен містити всі властивості:
const user: User = {
id: 1,
name: "Олена",
email: "olena@example.com"
};Якщо створити Partial<User>, кожна властивість стане необов’язковою:
type UserUpdate = Partial<User>;
const update: UserUpdate = {
name: "Олена Коваль"
};UserUpdate еквівалентний такому типу:
type UserUpdate = {
id?: number;
name?: string;
email?: string;
};Partial часто використовують для функцій, які оновлюють лише частину об’єкта:
interface User {
id: number;
name: string;
email: string;
}
function updateUser(user: User, changes: Partial<User>): User {
return {
...user,
...changes
};
}
const user: User = {
id: 1,
name: "Олена",
email: "olena@example.com"
};
const updatedUser = updateUser(user, {
name: "Олена Коваль"
});
console.log(updatedUser);У changes можна передати одну або кілька властивостей:
const firstUpdate = updateUser(user, {
name: "Ірина"
});
const secondUpdate = updateUser(user, {
email: "iryna@example.com"
});Але Partial не дозволяє передавати властивості, яких немає в початковому типі:
// Помилка TypeScript:
// const update = updateUser(user, {
// age: 25
// });Partial змінює властивості лише самого об’єкта, а не вкладених об’єктів.
interface Settings {
theme: string;
notifications: {
email: boolean;
sms: boolean;
};
}
type PartialSettings = Partial<Settings>;
const settings: PartialSettings = {
notifications: {
email: true,
sms: false
}
};Властивість notifications стала необов’язковою, але якщо її передати, то її властивості email і sms усе ще є обов’язковими:
// Помилка TypeScript:
// const settings: PartialSettings = {
// notifications: {
// email: true
// }
// };Required<Type> робить всі властивості типу обов’язковими.
Початковий тип може містити необов’язкові властивості:
interface FormData {
username: string;
password: string;
rememberMe?: boolean;
}Тип Required<FormData> зробить rememberMe обов’язковою:
type CompleteFormData = Required<FormData>;
const form: CompleteFormData = {
username: "olena",
password: "secret",
rememberMe: true
};CompleteFormData еквівалентний такому типу:
type CompleteFormData = {
username: string;
password: string;
rememberMe: boolean;
};Якщо не вказати rememberMe, TypeScript повідомить про помилку:
// Помилка TypeScript:
// const form: CompleteFormData = {
// username: "olena",
// password: "secret"
// };Required корисний, коли дані спочатку можуть бути неповними, але після перевірки програма працює вже з повним об’єктом:
interface AppConfig {
host?: string;
port?: number;
debug?: boolean;
}
function createConfig(): Required<AppConfig> {
return {
host: "localhost",
port: 3000,
debug: false
};
}
const config = createConfig();
console.log(config.host);
console.log(config.port);
console.log(config.debug);Функція повертає Required<AppConfig>, тому після її виконання TypeScript знає, що всі властивості існують.
Readonly<Type> робить всі властивості типу доступними лише для читання.
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = {
id: 1,
name: "Олена"
};
console.log(user.name);
// Помилки TypeScript:
// user.id = 2;
// user.name = "Ірина";Readonly<User> еквівалентний такому типу:
type ReadonlyUser = {
readonly id: number;
readonly name: string;
};Readonly зручно використовувати для об’єктів, які функція не повинна змінювати:
interface Product {
id: number;
name: string;
price: number;
}
function printProduct(product: Readonly<Product>): void {
console.log(`${product.name}: ${product.price} грн`);
// Помилка TypeScript:
// product.price = 0;
}
const product: Product = {
id: 1,
name: "Навушники",
price: 1200
};
printProduct(product);Тип параметра Readonly<Product> документує намір: функція може читати дані, але не повинна їх змінювати.
Utility types можна комбінувати.
Наприклад, можна створити тип об’єкта, властивості якого необов’язкові та доступні лише для читання:
interface User {
id: number;
name: string;
email: string;
}
type ReadonlyUserUpdate = Readonly<Partial<User>>;
const update: ReadonlyUserUpdate = {
name: "Олена"
};
console.log(update.name);
// Помилка TypeScript:
// update.name = "Ірина";У цьому випадку:
Partial<User> робить усі властивості необов’язковими;
Readonly<...> забороняє змінювати властивості.
Порядок застосування важливий для читабельності, але в цьому прикладі обидва модифікатори застосовуються до одного результату.
interface Profile {
id: number;
name: string;
email?: string;
}
// Усі властивості необов'язкові.
// Використовується для часткового оновлення профілю.
type ProfileUpdate = Partial<Profile>;
// Властивість email стає обов'язковою.
type CompleteProfile = Required<Profile>;
// Усі властивості доступні лише для читання.
type ReadonlyProfile = Readonly<Profile>;
function updateProfile(
profile: Profile,
changes: ProfileUpdate
): Profile {
return {
...profile,
...changes
};
}
const profile: Profile = {
id: 1,
name: "Олена"
};
const updatedProfile = updateProfile(profile, {
name: "Олена Коваль",
email: "olena@example.com"
});
const completeProfile: CompleteProfile = {
id: 1,
name: "Олена Коваль",
email: "olena@example.com"
};
const readonlyProfile: ReadonlyProfile = completeProfile;
console.log(updatedProfile);
console.log(readonlyProfile.name);
// Помилка TypeScript:
// readonlyProfile.name = "Ірина";Partial<Type>робить усі властивості необов’язковими;
додає до властивостей модифікатор ?;
часто використовується для часткового оновлення об’єкта.
Required<Type>робить усі властивості обов’язковими;
прибирає модифікатор ?;
корисний після заповнення або перевірки даних.
Readonly<Type>забороняє повторне присвоєння властивостям;
не змінює обов’язковість властивостей;
допомагає захистити об’єкт від змін у коді.
Наприклад:
interface Settings {
theme?: string;
}
type A = Partial<Settings>;
// theme?: string
type B = Required<Settings>;
// theme: string
type C = Readonly<Settings>;
// readonly theme?: stringPartial змінює лише властивості верхнього рівня. Вкладені властивості автоматично необов’язковими не стають.
interface User {
name: string;
address: {
city: string;
country: string;
};
}
type UserUpdate = Partial<User>;
const update: UserUpdate = {
address: {
city: "Львів",
country: "Україна"
}
};У цьому прикладі address можна не передавати, але якщо його передано, то city і country все ще обов’язкові.
Readonly — це перевірка TypeScript під час розробки. Вона не перетворює об’єкт на спеціальний незмінний об’єкт під час виконання JavaScript.
interface Counter {
value: number;
}
const counter: Readonly<Counter> = {
value: 0
};
// TypeScript не дозволяє:
// counter.value = 1;Головне призначення Readonly — не допустити випадкових змін у коді, який перевіряє TypeScript.
Після застосування Required усі необов’язкові властивості потрібно передати:
interface Options {
color?: string;
size?: number;
}
type CompleteOptions = Required<Options>;
// Помилка TypeScript:
// const options: CompleteOptions = {
// color: "blue"
// };Потрібно вказати і color, і size:
const options: CompleteOptions = {
color: "blue",
size: 10
};Partial<Type> робить усі властивості необов’язковими.
Required<Type> робить усі властивості обов’язковими.
Readonly<Type> забороняє змінювати властивості через TypeScript.
Partial зручний для часткових оновлень об’єктів.
Required допомагає описати повністю заповнені дані.
Readonly захищає дані від випадкової зміни.
Utility types можна комбінувати, наприклад Readonly<Partial<User>>.
Partial працює лише з властивостями верхнього рівня.