Пошук уроків, статей та іншого контенту
Задайте типи параметрів, результату та контексту виконання звичайних і стрілкових функцій.
Типізація функцій допомагає заздалегідь описати:
які значення функція приймає;
яке значення повертає;
який тип має контекст this;
які функції можна передавати як аргументи.
Завдяки цьому TypeScript перевіряє виклики функцій ще до запуску програми.
function add(first: number, second: number): number {
return first + second;
}
const result = add(2, 3);
console.log(result); // 5У цьому прикладі:
first: number — тип першого параметра;
second: number — тип другого параметра;
: number після дужок — тип результату функції.
Тип параметра записують після його назви через двокрапку:
function greet(name: string, age: number): string {
return `${name} має ${age} років`;
}
console.log(greet("Олена", 25));Якщо передати значення неправильного типу, TypeScript повідомить про помилку:
greet("Олена", "25");
// Помилка: аргумент типу string не можна передати параметру типу numberКожен параметр може мати власний тип:
function createUser(name: string, isAdmin: boolean, score: number): string {
return `${name}: admin=${isAdmin}, score=${score}`;
}
console.log(createUser("Іван", true, 100));Для об'єкта можна описати структуру безпосередньо в параметрі:
function printUser(user: { name: string; age: number }): string {
return `${user.name}, ${user.age} років`;
}
console.log(printUser({ name: "Марія", age: 30 }));Якщо структура використовується кілька разів, зручніше створити окремий тип:
type User = {
name: string;
age: number;
};
function printUser(user: User): string {
return `${user.name}, ${user.age} років`;
}
const user: User = {
name: "Марія",
age: 30,
};
console.log(printUser(user));Тип результату записують після закриваючої дужки параметрів:
function multiply(first: number, second: number): number {
return first * second;
}Функція повинна повертати значення відповідного типу:
function getMessage(): string {
return "Готово";
}Такий код буде помилковим:
function getMessage(): string {
return 42;
}TypeScript очікує string, але отримує number.
Якщо функція нічого не повертає, для неї використовують тип void:
function logMessage(message: string): void {
console.log(message);
}Функція з типом void може не містити return або мати return без значення:
function showStatus(isOnline: boolean): void {
if (isOnline) {
console.log("Користувач онлайн");
return;
}
console.log("Користувач офлайн");
}void означає, що результат функції не призначений для використання:
const result = logMessage("Привіт");
console.log(result); // undefinedTypeScript часто може визначити тип результату самостійно:
function subtract(first: number, second: number) {
return first - second;
}TypeScript виводить, що результат має тип number.
Також він може вивести тип параметра в колбеку, якщо контекст функції вже відомий:
function processValue(value: number, transform: (value: number) => number): number {
return transform(value);
}
const result = processValue(5, (value) => value * 2);
console.log(result); // 10У стрілковій функції value автоматично має тип number, тому що параметр transform описаний як функція, яка приймає number.
Попри це, тип результату функції часто варто вказувати явно. Це:
робить код зрозумілішим;
документує призначення функції;
допомагає помітити помилку всередині функції.
Стрілкова функція типізується так само, як звичайна:
const square = (value: number): number => {
return value * value;
};
console.log(square(4)); // 16Для короткого запису можна використати неявне повернення:
const double = (value: number): number => value * 2;
console.log(double(6)); // 12Якщо функція має кілька параметрів, кожен параметр потрібно типізувати:
const divide = (first: number, second: number): number => {
return first / second;
};Функцію можна описати окремим типом:
type Operation = (first: number, second: number) => number;
const add: Operation = (first, second) => first + second;
const multiply: Operation = (first, second) => first * second;
console.log(add(2, 3)); // 5
console.log(multiply(2, 3)); // 6Тип Operation означає:
функція приймає два параметри типу number;
функція повертає number.
Такий запис зручний, коли кілька функцій мають однакову структуру.
Функція може приймати іншу функцію як параметр. Для цього потрібно описати тип функції:
function applyOperation(
first: number,
second: number,
operation: (a: number, b: number) => number
): number {
return operation(first, second);
}
const sum = applyOperation(10, 5, (a, b) => a + b);
const difference = applyOperation(10, 5, (a, b) => a - b);
console.log(sum); // 15
console.log(difference); // 5Параметр operation має тип:
(a: number, b: number) => numberТобто він повинен бути функцією з двома числовими параметрами та числовим результатом.
Необов'язковий параметр позначають знаком ?:
function greetUser(name: string, greeting?: string): string {
const message = greeting ?? "Привіт";
return `${message}, ${name}!`;
}
console.log(greetUser("Олена"));
console.log(greetUser("Олена", "Доброго ранку"));Параметр greeting має тип string | undefined, тому що під час виклику його можна не передати.
Необов'язкові параметри повинні розташовуватися після обов'язкових:
function createLabel(text: string, color?: string): string {
return color ? `${text} (${color})` : text;
}Параметр може мати значення за замовчуванням:
function repeatText(text: string, count: number = 1): string {
return text.repeat(count);
}
console.log(repeatText("Hi")); // Hi
console.log(repeatText("Hi", 3)); // HiHiHiТип параметра вказано як number, а якщо значення не передано, використовується 1.
Якщо функція приймає довільну кількість аргументів, використовують rest-параметр. Його типом буде масив:
function sum(...numbers: number[]): number {
return numbers.reduce((total, number) => total + number, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100...numbers: number[] означає, що всі додаткові аргументи повинні бути числами.
thisУ звичайній функції значення this залежить від способу виклику функції. TypeScript дозволяє явно описати тип this за допомогою спеціального першого параметра:
type User = {
name: string;
};
function getUserLabel(this: User, prefix: string): string {
return `${prefix}: ${this.name}`;
}
const user: User = {
name: "Олена",
};
const label = getUserLabel.call(user, "Користувач");
console.log(label); // Користувач: ОленаПараметр this має особливе призначення:
function getUserLabel(this: User, prefix: string): string {
return `${prefix}: ${this.name}`;
}Він використовується лише для перевірки типів і не стає звичайним аргументом функції. Тому виклик через call передає user як контекст, а "Користувач" — як параметр prefix.
Не можна викликати цю функцію так:
getUserLabel(user, "Користувач");
// Помилка: user не є параметром функціїthis у методах об'єктаТип контексту можна описати в типі методу:
type Counter = {
value: number;
increase(this: Counter, amount: number): number;
};
const counter: Counter = {
value: 0,
increase(amount) {
this.value += amount;
return this.value;
},
};
console.log(counter.increase(5)); // 5
console.log(counter.increase(3)); // 8У методі increase:
this має тип Counter;
amount має тип number;
результат має тип number, оскільки так описано в типі Counter.
Контекстом this під час виклику counter.increase(5) є об'єкт counter.
this у стрілкових функціяхСтрілкові функції не створюють власного this. Вони використовують this із зовнішнього контексту.
Тому спеціальний параметр this не можна додати до стрілкової функції:
// Некоректний підхід:
// const getName = (this: User): string => this.name;Якщо стрілкова функція повинна працювати з об'єктом, зазвичай передають цей об'єкт звичайним параметром:
type User = {
name: string;
};
const getName = (user: User): string => {
return user.name;
};
const user: User = {
name: "Іван",
};
console.log(getName(user));Це робить залежність функції явною: для роботи їй потрібен параметр user.
type User = {
name: string;
};
function getNameWithThis(this: User): string {
return this.name;
}
const getNameWithParameter = (user: User): string => {
return user.name;
};
const user: User = {
name: "Марія",
};
console.log(getNameWithThis.call(user));
console.log(getNameWithParameter(user));У першому варіанті ім'я береться з this, у другому — зі звичайного параметра.
Для простих функцій передавання об'єкта параметром часто зрозуміліше, оскільки функція не залежить від способу виклику.
type Product = {
name: string;
price: number;
};
type Formatter = (product: Product) => string;
function formatProduct(product: Product, formatter: Formatter): string {
return formatter(product);
}
const product: Product = {
name: "Ноутбук",
price: 45000,
};
const label = formatProduct(product, (item): string => {
return `${item.name}: ${item.price} грн`;
});
console.log(label); // Ноутбук: 45000 грн
type ShoppingCart = {
items: Product[];
getTotal(this: ShoppingCart): number;
};
const cart: ShoppingCart = {
items: [
{ name: "Миша", price: 800 },
{ name: "Клавіатура", price: 2200 },
],
getTotal() {
return this.items.reduce((total, item) => total + item.price, 0);
},
};
console.log(cart.getTotal()); // 3000У прикладі типізовано:
властивості об'єктів Product;
функцію-форматер Formatter;
параметри й результат formatProduct;
контекст this методу getTotal;
параметри стрілкової функції.
function printValue(value) {
console.log(value);
}За суворих налаштувань TypeScript параметр без типу може спричинити помилку про неявний тип any.
Правильніше:
function printValue(value: string): void {
console.log(value);
}function getCount(): number {
return "10";
}Результат повинен відповідати типу number:
function getCount(): number {
return 10;
}function calculateTax(price: number, rate: number): number {
return price * rate;
}
calculateTax("100", 0.2);
// Помилка: перший аргумент має бути numberthis і звичайним параметромtype Account = {
owner: string;
};
function getOwner(this: Account): string {
return this.owner;
}
// getOwner(account) — помилкаПараметр this не передають у звичайному виклику. Для нього потрібен контекст:
const account: Account = {
owner: "Іван",
};
console.log(getOwner.call(account));this у стрілковій функціїСтрілкова функція не має власного this. Якщо їй потрібен об'єкт, передайте його звичайним параметром:
const getOwner = (account: Account): string => {
return account.owner;
};Створіть функцію calculateTotal, яка:
приймає масив товарів;
приймає функцію для обчислення ціни одного товару;
повертає загальну суму типу number.
Опис товару:
type Product = {
name: string;
price: number;
quantity: number;
};Можливий результат:
type Product = {
name: string;
price: number;
quantity: number;
};
function calculateTotal(
products: Product[],
getItemTotal: (product: Product) => number
): number {
return products.reduce((total, product) => {
return total + getItemTotal(product);
}, 0);
}
const products: Product[] = [
{ name: "Книга", price: 300, quantity: 2 },
{ name: "Зошит", price: 50, quantity: 3 },
];
const total = calculateTotal(
products,
(product): number => product.price * product.quantity
);
console.log(total); // 750Тип параметра записують після його назви: value: string.
Тип результату записують після списку параметрів: (): number.
Для функції без корисного результату використовують void.
Тип функції має форму (параметри) => результат.
Функції можна передавати як аргументи, явно описуючи їхню сигнатуру.
Необов'язкові параметри позначають ?.
Rest-параметри типізують як масив, наприклад ...values: number[].
Тип this у звичайній функції задають спеціальним першим параметром this: SomeType.
Стрілкові функції не мають власного this; потрібний об'єкт зазвичай передають звичайним параметром.