Перегрузка функций позволяет создать одну функцию с разными вариантами принимаемых параметров и возвращаемого значения. В других языках, как C# или Java, можно описывать несколько функций с одним именем, но с разными типами или количеством аргументов. TypeScript приближает этот механизм через перегрузку сигнатур на уровне типов, но тело функции всегда одно.
История вопроса — в JavaScript нет нативной поддержки перегрузки по типу или количеству параметров. С появлением TypeScript перегрузка эмулируется через объявление нескольких сигнатур функции подряд и единственной реализацией, внутри которой вручную отличают, с каким типом сейчас работают.
Проблема возникает, если не следить за соответствием объявленным сигнатурам: параметрам внутри тела функции TypeScript присваивает самый общий тип (объединение всех типов параметров) и программист должен делать проверки и type guards.
Решение: Строго типизировать перегрузки в явных сигнатурах, грамотно работать с union types и type guards, корректно документировать поведение.
Пример кода:
function format(value: string): string; function format(value: number, locale: string): string; function format(value: any, locale?: string): string { if (typeof value === 'number') { return value.toLocaleString(locale); } return value.trim(); } format(' hello '); // 'hello' format(123456, 'ru-RU'); // '123 456'
Ключевые особенности:
Можно ли объявить несколько функций с одним именем и разными телами, как в C#?»
Нет. В TypeScript (и в JavaScript) фактически реально существует только одна функция с этим именем. Перегрузки работают только на уровне типов для компилятора, но есть только одно тело функции.
Что будет, если не реализовать сигнатуру с самыми общими параметрами после перегружающих сигнатур?
TypeScript выдаст ошибку компиляции. Всегда должна быть одна функция-реализация, параметры которой перекрывают все возможные варианты перегрузок.
function foo(a: string): string; function foo(a: number): number; // нет тела — ошибка
Могу ли я внутри тела использовать свойства, специфичные для одной конкретной сигнатуры?
Нет, только после проверки типа (type guard) или приведения типа. Иначе TypeScript не разрешит использовать эти свойства напрямую, так как не известно, по какой сигнатуре сейчас идет вызов.
function bar(x: string): number; function bar(x: number): number; function bar(x: string | number): number { if (typeof x === 'string') return x.length; return x * 2; }
Забыли добавить универсальную сигнатуру-реализацию:
function sum(a: string, b: string): string; function sum(a: number, b: number): number; // нет реализации — компилятор ругается
Плюсы:
Минусы:
Реализуют перегрузку согласно стандарту:
function sum(a: string, b: string): string; function sum(a: number, b: number): number; function sum(a: any, b: any): any { return typeof a === 'string' && typeof b === 'string' ? a + b : a + b; }
Плюсы:
Минусы: