Параметры: необязательные, по умолчанию, остаточные
tsc не пропускает вызов area(3) у функции с двумя параметрами: аргументов должно быть столько же, сколько параметров. Но в JavaScript много функций, у которых аргумент можно не передавать. greet() здоровается с гостем, а greet("Аня") — с Аней. Как сказать об этом в сигнатуре?
Вернёмся к автомату с чаем. Кроме монетоприёмника, у него есть кнопки, и на табличке про них тоже написано:
- «Сахар — по желанию»: кнопку можно не нажимать, и тогда сахара не будет;
- «Не выбрали размер — нальём средний»: если кнопку не нажали, автомат сам выберет обычный вариант;
- «Принимает любое число монет»: бросайте сколько угодно, автомат посчитает все.
В TypeScript у каждой из этих строк таблички есть своя запись.
Три вида параметров
Необязательный параметр
Знак ? после имени параметра говорит: аргумент можно не передавать.
function greet(name?: string): string {
if (name === undefined) {
return "Привет, гость!";
}
return "Привет, " + name.toUpperCase() + "!";
}
console.log(greet()); // Привет, гость!
console.log(greet("Аня")); // Привет, АНЯ!Разберём, что изменилось:
name?: string— параметр необязательный, поэтому оба вызова,greet()иgreet("Аня"), проходят проверку.- Внутри функции у
nameтипstring | undefined: если аргумент не передали, тамundefined. Так же читалось необязательное свойствоage?: numberв пятой теме. - Проверка
name === undefinedсужает тип, и после неёname— ужеstring, у которого естьtoUpperCase.
Уберите проверку, и tsc остановит вызов метода:
error TS18048: 'name' is possibly 'undefined'.Сообщение значит: «name может быть undefined». Необязательные параметры пишут после обязательных: в сигнатуре (greeting?: string, name: string) tsc сообщит об ошибке TS1016 — обязательный параметр не может идти после необязательного.
Значение по умолчанию
Если без аргумента функция должна взять обычное значение, его пишут прямо в параметре, как в JavaScript:
function greet(name = "гость"): string {
return "Привет, " + name + "!";
}
console.log(greet()); // Привет, гость!
console.log(greet("Аня")); // Привет, Аня!
console.log(greet(undefined)); // Привет, гость!Тип параметра TypeScript вывел из значения по умолчанию: name — это string. Внутри функции name всегда строка, проверять его не нужно. А для вызывающего кода параметр необязательный: подсказка над greet покажет function greet(name?: string): string.
Значение по умолчанию подставляется, когда аргумент равен undefined. Неважно, не передали его вовсе или передали undefined явно, как в третьем вызове.
Остаточный параметр
Параметр с тремя точками перед именем — остаточный параметр: он собирает все оставшиеся аргументы в массив.
function sum(...nums: number[]): number {
let total = 0;
for (const n of nums) {
total += n;
}
return total;
}
console.log(sum()); // 0
console.log(sum(1, 2, 3)); // 6У остаточного параметра тип массива: nums: number[]. Число аргументов теперь любое, даже ноль, но каждый должен быть числом. sum(1, "2") даст знакомую ошибку TS2345: строку нельзя передать вместо number. Остаточный параметр бывает только последним.
? или значение по умолчанию
На собеседовании часто спрашивают, чем необязательный параметр отличается от параметра со значением по умолчанию. Оба разрешают не передавать аргумент, а разница — в типе внутри функции:
name?: string— внутри функции типstring | undefined, и перед использованием нужна проверка;name = "гость"— внутри функции типstring, и проверка не нужна.
Здесь аналогия с автоматом заканчивается. У настоящего автомата «не нажали кнопку» и «нажали „без сахара“» — разные действия. В JavaScript пропущенный аргумент и явный undefined неразличимы: значение по умолчанию сработает в обоих случаях.
Частая ошибка
Знак ? и значение по умолчанию поставили на один параметр, чтобы подчеркнуть, что он необязательный:
function greet(name?: string = "гость"): string { // ✗
return "Привет, " + name + "!";
}error TS1015: Parameter cannot have question mark and initializer.Сообщение значит: «у параметра не может быть одновременно знака вопроса и начального значения». Значение по умолчанию уже делает параметр необязательным, поэтому ? здесь лишний: достаточно name = "гость".
Главное
name?: string— необязательный параметр; внутри функции его типstring | undefined, и перед использованием его проверяют.name = "гость"— значение по умолчанию; тип внутри функцииstring, а подставляется значение, когда аргумент равенundefined....nums: number[]собирает оставшиеся аргументы в массив; каждый аргумент проверяется по типу элемента.- Необязательные параметры и остаточный параметр идут последними, а
?и значение по умолчанию на одном параметре не совмещают.