Типы функций
В JavaScript функция — это значение. Её можно сохранить в переменную, как вы делаете со стрелочными функциями, и передать в другую функцию как аргумент. В TypeScript у каждого значения есть тип, а значит, он есть и у функции. Тип функции
const critical = (power: number): number => power * 2;— это (power: number) => number: «функция, которая принимает число и возвращает число». Он похож на стрелочную функцию, но после стрелки стоит возвращаемый тип, а не тело. Такие типы вы увидите в сообщениях об ошибках, например когда попробуете сохранить в переменную что-то другое:
let spell = (target: string): string => `Огонь поражает: ${target}`;
spell = 5;main.ts(2,1): error TS2322: Type 'number' is not assignable to type '(target: string) => string'.Типы функций нужны для параметров, в которых хранится функция. Кира может бить по-разному, а функция attackMonster принимает способ удара как аргумент:
function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
return `Кира бьёт монстра «${monster}»: урон ${strike(power)}`;
}
const normal = (power: number): number => power;
const critical = (power: number): number => power * 2;
console.log(attackMonster("гоблин", 10, normal));
console.log(attackMonster("тролль", 10, critical));Это выведет:
Кира бьёт монстра «гоблин»: урон 10
Кира бьёт монстра «тролль»: урон 20Внутри функции strike — такой же параметр, как и любой другой, но в нём хранится функция, поэтому её можно вызвать: strike(power). При вызове передавайте саму функцию, без скобок: critical, а не critical(10). Со скобками вы вызвали бы её сразу и передали бы её результат, число 20:
function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
return `Кира бьёт монстра «${monster}»: урон ${strike(power)}`;
}
const normal = (power: number): number => power;
const critical = (power: number): number => power * 2;
console.log(attackMonster("тролль", 10, critical(10)));main.ts(8,41): error TS2345: Argument of type 'number' is not assignable to parameter of type '(power: number) => number'.TypeScript проверяет и то, что у переданной функции подходящая форма. Функция, которой нужна строка, не подойдёт:
function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
return `Кира бьёт монстра «${monster}»: урон ${strike(power)}`;
}
const normal = (power: number): number => power;
const critical = (power: number): number => power * 2;
const shout = (text: string): string => text.toUpperCase();
console.log(attackMonster("волк", 10, shout));main.ts(10,39): error TS2345: Argument of type '(text: string) => string' is not assignable to parameter of type '(power: number) => number'.
Types of parameters 'text' and 'power' are incompatible.
Type 'number' is not assignable to type 'string'.Строки с отступом объясняют причину: параметры text и power не сочетаются. attackMonster вызовет функцию с числом, а shout ждёт строку.
Длинный тип функции затрудняет чтение списка параметров. Дайте ему имя с помощью type:
type Strike = (power: number) => number;
function attackMonster(monster: string, power: number, strike: Strike): string {type создаёт псевдоним типа (type alias): новое имя для типа. Strike теперь означает (power: number) => number, и сообщения об ошибках используют новое имя (parameter of type 'Strike'). По соглашению имена типов начинаются с заглавной буквы. В уроке об объектных типах вы будете часто использовать псевдонимы типов, в основном для объектов.
Псевдоним можно использовать и для переменной. Тогда параметру стрелочной функции собственный тип не нужен: TypeScript возьмёт его из Strike:
const critical: Strike = (power) => power * 2;Вы встретитесь с этим снова в следующем упражнении.
Задание
- 1
В начале программы создайте псевдоним типа
PriceRuleдля функции, которая принимает числоpriceи возвращает число. - 2
Напишите функцию
priceTagс тремя параметрами:itemтипаstring,priceтипаnumberиruleтипаPriceRule. Она возвращает строку видаВерёвка: 5 золота, где цена — результатrule(price). - 3
Выведите
priceTag("Серебряный меч", 120, normalPrice),priceTag("Целебное зелье", 40, sale)иpriceTag("Верёвка", 10, guildPrice). Программа выведет:Серебряный меч: 120 золота Целебное зелье: 20 золота Верёвка: 5 золота - 4
В рыночные дни всё дорожает на 10 золота. Создайте правило
marketDayс типомPriceRule, чтобы его параметру не нужен был собственный тип:const marketDay: PriceRule = (price) => .... Затем выведитеpriceTag("Фонарь", 15, marketDay): это выведетФонарь: 25 золота.