Перевантаження описують кілька способів викликати функцію з різними типами результату залежно від аргументів. Складаються з кількох сигнатур і однієї реалізації:
function parse(value: string): number;
function parse(value: number): string;
function parse(value: string | number): string | number {
return typeof value === 'string' ? Number(value) : String(value);
}
parse('42'); // number
parse(42); // string
Правила:
- реалізація ззовні не видна - викликати функцію можна лише за сигнатурами перевантажень. Сигнатура реалізації має бути сумісною з усіма ними;
- TypeScript перебирає перевантаження по черзі й бере перше відповідне - тому конкретніші ставлять вище за загальніші;
- реалізація сама перевіряє, з яким варіантом її викликали (
typeof,in), - компілятор не перевіряє, що кожна гілка повертає «правильний» тип для своєї сигнатури.
Головна пастка - аргумент-об'єднання:
declare const input: string | number;
parse(input); // помилка: жодне перевантаження не приймає string | number
Кожне перевантаження приймає лише свій тип, а об'єднання не підходить жодному. Доводиться додавати ще одну сигнатуру (value: string | number): string | number.
Коли краще без перевантажень:
- результат не залежить від типу аргументу - звичайний тип-об'єднання;
- результат залежить від аргументу передбачувано - generic чи умовний тип:
function first<T>(items: T[]): T | undefined {
return items[0];
}
- різні способи виклику з різною кількістю параметрів - часто краще об'єкт параметрів чи кілька окремих функцій з виразними назвами (
parseNumber,formatNumber).
Коли перевантаження доречні:
- типи для API, яке вже так влаштоване - бібліотеки,
.d.tsдля JavaScript-коду (document.createElement('canvas')повертаєHTMLCanvasElement- перевантаження в типах DOM); - залежність результату від літерального значення аргументу, яку незручно виразити умовним типом.
Перевантаження методів класу пишуться так само, а в типах об'єктів - кількома сигнатурами виклику.