Пошук уроків, статей та іншого контенту
Типізуйте необов'язкові параметри та параметри зі значеннями за замовчуванням без втрати безпеки.
Необов’язковий параметр може бути відсутнім під час виклику функції. У TypeScript для цього використовують знак ? після імені параметра:
function greet(name?: string): string {
if (name === undefined) {
return "Привіт, незнайомцю!";
}
return `Привіт, ${name}!`;
}
console.log(greet("Олена"));
console.log(greet());Тип параметра name у цій функції фактично є string | undefined. Тому TypeScript не дозволить використовувати його як звичайний string без перевірки:
function printName(name?: string): void {
// Помилка:
// Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
// console.log(name.toUpperCase());
if (name !== undefined) {
console.log(name.toUpperCase());
}
}Перевірка name !== undefined звужує тип параметра з string | undefined до string. Після цього безпечно викликати методи рядка.
Необов’язковий параметр позначається ?:
function createMessage(message: string, prefix?: string): string {
if (prefix === undefined) {
return message;
}
return `${prefix}: ${message}`;
}
console.log(createMessage("Збережено"));
console.log(createMessage("Збережено", "Успіх"));Необов’язкові параметри повинні розташовуватися після обов’язкових:
// Правильно
function search(query: string, limit?: number): void {
console.log(query, limit);
}
// Помилка: обов’язковий параметр не може йти після необов’язкового
// function invalid(limit?: number, query: string): void {}Інакше виклик функції стає неоднозначним: TypeScript не може зрозуміти, як передати значення лише для наступного обов’язкового параметра.
Параметр зі значенням за замовчуванням отримує це значення, якщо під час виклику передано undefined або аргумент не передано:
function connect(host: string, port = 3000): string {
return `Підключення до ${host}:${port}`;
}
console.log(connect("localhost"));
console.log(connect("localhost", 8080));
console.log(connect("localhost", undefined));Результат:
Підключення до localhost:3000
Підключення до localhost:8080
Підключення до localhost:3000TypeScript виводить тип параметра port зі значення за замовчуванням. У цьому прикладі port має тип number всередині функції.
function repeat(text: string, count = 1): string {
// count має тип number
return text.repeat(count);
}Параметр зі значенням за замовчуванням також вважається необов’язковим під час виклику:
function getPage(page = 1): number {
return page;
}
getPage();
getPage(3);Окремо позначати такий параметр знаком ? не потрібно:
// Надлишково й некоректно
// function getPage(page?: number = 1): number {}Потрібно вибрати один із підходів:
function getPageWithOptionalParameter(page?: number): number {
return page ?? 1;
}
function getPageWithDefaultParameter(page = 1): number {
return page;
}? і значенням за замовчуваннямОбидва підходи дозволяють не передавати аргумент, але вони по-різному організовують код.
Для необов’язкового параметра значення undefined потрібно обробити вручну:
function formatPrice(price?: number): string {
if (price === undefined) {
return "Ціна не вказана";
}
return `${price.toFixed(2)} грн`;
}Значення за замовчуванням автоматично замінює undefined:
function formatPrice(price = 0): string {
return `${price.toFixed(2)} грн`;
}
console.log(formatPrice());
console.log(formatPrice(undefined));
console.log(formatPrice(149.5));Вибір залежить від змісту параметра:
використовуйте ?, якщо відсутність значення має окреме значення;
використовуйте значення за замовчуванням, якщо функція має передбачувану стандартну поведінку.
undefined і nullЗначення за замовчуванням застосовується для undefined, але не для null:
function getTimeout(timeout = 5000): number {
return timeout;
}
console.log(getTimeout()); // 5000
console.log(getTimeout(undefined)); // 5000
console.log(getTimeout(null)); // Помилка типів у TypeScriptЗа стандартних налаштувань TypeScript null не сумісний із number. Якщо проєкт дозволяє null, його все одно не буде автоматично замінено значенням за замовчуванням на рівні JavaScript:
function getTimeoutValue(timeout: number | null = 5000): number | null {
return timeout;
}
console.log(getTimeoutValue(null)); // nullЯкщо null також потрібно трактувати як відсутність значення, це слід зробити явно:
function normalizeTimeout(timeout?: number | null): number {
return timeout ?? 5000;
}
console.log(normalizeTimeout());
console.log(normalizeTimeout(undefined));
console.log(normalizeTimeout(null));
console.log(normalizeTimeout(1000));Оператор ?? повертає значення праворуч лише тоді, коли значення ліворуч дорівнює null або undefined.
Тип значення за замовчуванням має відповідати типу параметра:
function createUser(name: string, age = 18): {
name: string;
age: number;
} {
return { name, age };
}Якщо потрібно явно вказати тип, це можна зробити так:
function createUserWithRole(
name: string,
role: string = "user"
): { name: string; role: string } {
return { name, role };
}Тип параметра має бути сумісним зі значенням за замовчуванням:
// Помилка: string не сумісний із number
// function getLimit(limit: number = "10"): number {
// return limit;
// }Значення за замовчуванням може залежати від попереднього параметра:
function createRange(start: number, end = start + 10): number[] {
const result: number[] = [];
for (let value = start; value <= end; value += 1) {
result.push(value);
}
return result;
}
console.log(createRange(5));
console.log(createRange(5, 7));Параметр, який використовується у значенні за замовчуванням, повинен бути оголошений раніше:
// Правильно
function getEnd(start: number, end = start + 1): number {
return end;
}
// Помилка: start оголошено після end
// function getInvalid(end = start + 1, start: number): number {
// return end;
// }Якщо потрібно пропустити необов’язковий параметр і передати значення наступному, безпосередньо це зробити не можна. Аргументи функції передаються позиційно.
function configure(host: string, port?: number, secure?: boolean): void {
console.log({ host, port, secure });
}
configure("localhost", 3000, true);
configure("localhost", undefined, true);У другому виклику undefined явно пропускає параметр port, а true потрапляє до secure.
Якщо параметрів багато або вони мають різні необов’язкові комбінації, для них часто використовують один об’єкт параметрів:
type RequestOptions = {
timeout?: number;
retries?: number;
secure?: boolean;
};
function request(url: string, options: RequestOptions = {}): void {
const timeout = options.timeout ?? 5000;
const retries = options.retries ?? 3;
const secure = options.secure ?? true;
console.log({
url,
timeout,
retries,
secure,
});
}
request("/api/users");
request("/api/users", {
timeout: 10000,
secure: false,
});Такий підхід дозволяє передавати властивості за іменами та не використовувати undefined для пропуску позицій.
Під час опису типу функції необов’язковий параметр також позначається ?:
type Logger = (message: string, level?: "info" | "error") => void;
const log: Logger = (message, level = "info") => {
console.log(`[${level}] ${message}`);
};
log("Сервер запущено");
log("Не вдалося підключитися", "error");Параметр у реалізації може мати значення за замовчуванням, навіть якщо в типі функції він описаний як необов’язковий.
Водночас тип функції має бути сумісним із її реалізацією:
type Formatter = (value: string, prefix?: string) => string;
const format: Formatter = (value, prefix) => {
return prefix === undefined ? value : `${prefix}${value}`;
};Оскільки prefix може бути відсутнім, реалізація повинна безпечно працювати з undefined.
Нижче функція створює опис повідомлення. Перший параметр обов’язковий, а решта мають значення за замовчуванням:
type MessageOptions = {
author?: string;
important?: boolean;
};
function buildMessage(
text: string,
options: MessageOptions = {}
): string {
const author = options.author ?? "Система";
const marker = options.important === true ? "!" : "";
return `[${author}] ${text}${marker}`;
}
console.log(buildMessage("Файл збережено"));
console.log(
buildMessage("Потрібна увага", {
author: "Адміністратор",
important: true,
})
);Тут:
text є обов’язковим параметром;
options має значення {} за замовчуванням;
author може бути відсутнім;
important може бути відсутнім;
оператор ?? безпечно задає стандартне ім’я автора;
перевірка options.important === true не плутає false, undefined та true.
function uppercase(value?: string): string {
// Помилка:
// return value.toUpperCase();
return value === undefined ? "" : value.toUpperCase();
}Необов’язковий параметр завжди може бути undefined, тому його потрібно перевірити або замінити значенням за замовчуванням.
|| замість ??Оператор || вважає відсутніми всі falsy-значення: 0, false, "", null і undefined.
function getLimitWithOr(limit?: number): number {
return limit || 10;
}
function getLimitWithNullish(limit?: number): number {
return limit ?? 10;
}
console.log(getLimitWithOr(0)); // 10
console.log(getLimitWithNullish(0)); // 0Якщо 0, false або порожній рядок є коректними значеннями, використовуйте ??.
null активує значення за замовчуваннямfunction getName(name = "Гість"): string {
return name;
}
console.log(getName(undefined)); // "Гість"
// getName(null); // Помилка типівЗначення за замовчуванням спрацьовує для undefined, але не для null.
?Не потрібно поєднувати ? і значення за замовчуванням:
// Некоректний синтаксис
// function load(page?: number = 1): void {}Використовуйте:
function load(page = 1): void {
console.log(page);
}// Помилка
// function send(subject?: string, recipient: string): void {}Обов’язкові параметри мають іти перед необов’язковими.
Використовуйте ?, коли потрібно відрізняти відсутність значення від конкретного стандартного значення.
Використовуйте значення за замовчуванням, коли функція має готову стандартну поведінку.
Пам’ятайте, що необов’язковий параметр має тип із undefined.
Перевіряйте необов’язкові параметри перед доступом до їхніх властивостей і методів.
Для null і undefined використовуйте ??, якщо обидва значення повинні означати «значення відсутнє».
Якщо функція має багато необов’язкових параметрів, передавайте їх одним типізованим об’єктом.
Не покладайтеся лише на перевірку типів: під час виконання JavaScript значення все одно можуть надходити з зовнішніх джерел.
parameter?: Type означає, що параметр може бути відсутнім і має тип Type | undefined.
Параметри зі знаком ? повинні розташовуватися після обов’язкових параметрів.
parameter = value задає значення за замовчуванням і робить параметр необов’язковим під час виклику.
Значення за замовчуванням застосовується для аргументу undefined, але не для null.
TypeScript автоматично виводить тип параметра зі значення за замовчуванням.
Необов’язкове значення потрібно перевірити або безпечно обробити перед використанням.
Для складних наборів необов’язкових налаштувань зручно використовувати типізований об’єкт параметрів.