Function Types

In JavaScript, a function is a value. You can store it in a variable, as you do with arrow functions, and pass it to another function as an argument. In TypeScript, every value has a type, so a function has one too. The type of

const critical = (power: number): number => power * 2;

is (power: number) => number: “a function that takes a number and returns a number”. It looks like an arrow function, but after the arrow comes the return type, not the body. You'll see such types in error messages, for example when you try to store something else in the variable:

let spell = (target: string): string => `Fire hits the ${target}`;
spell = 5;
main.ts(2,1): error TS2322: Type 'number' is not assignable to type '(target: string) => string'.

Function types are needed for parameters that hold a function. Kira can strike in different ways, and the function attackMonster takes the way of striking as an argument:

function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
    return `Kira hits the ${monster} for ${strike(power)}`;
}

const normal = (power: number): number => power;
const critical = (power: number): number => power * 2;

console.log(attackMonster("goblin", 10, normal));
console.log(attackMonster("troll", 10, critical));

This prints:

Kira hits the goblin for 10
Kira hits the troll for 20

Inside, strike is a parameter like any other, but it holds a function, so you call it: strike(power). In the call, pass the function itself, without parentheses: critical, not critical(10). With parentheses, you'd call it right away and pass its result, the number 20:

function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
    return `Kira hits the ${monster} for ${strike(power)}`;
}

const normal = (power: number): number => power;
const critical = (power: number): number => power * 2;

console.log(attackMonster("troll", 10, critical(10)));
main.ts(8,40): error TS2345: Argument of type 'number' is not assignable to parameter of type '(power: number) => number'.

TypeScript also checks that the function you pass has the right shape. A function that wants a text doesn't fit:

function attackMonster(monster: string, power: number, strike: (power: number) => number): string {
    return `Kira hits the ${monster} for ${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("wolf", 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'.

The indented lines explain why: the parameters text and power don't fit together. attackMonster will call the function with a number, but shout wants a string.

A long function type makes the parameter list hard to read. Give it a name with type:

type Strike = (power: number) => number;

function attackMonster(monster: string, power: number, strike: Strike): string {

type creates a type alias: a new name for a type. Strike now means (power: number) => number, and error messages use the new name (parameter of type 'Strike'). By convention, type names start with a capital letter. In the next lesson, you'll use type aliases a lot, mostly for objects.

You can use the alias for a variable too. Then the arrow function's parameter needs no type of its own: TypeScript takes it from Strike:

const critical: Strike = (power) => power * 2;

You'll see this again in the next exercise.

Instructions

At the top of the program, create a type alias PriceRule for a function that takes a number price and returns a number.

Write a function priceTag with three parameters: item of type string, price of type number and rule of type PriceRule. It returns a text such as Rope: 5 gold, where the price is the result of rule(price).

Print priceTag("Silver Sword", 120, normalPrice), priceTag("Healing Potion", 40, sale) and priceTag("Rope", 10, guildPrice). The program prints:

Silver Sword: 120 gold
Healing Potion: 20 gold
Rope: 5 gold

On market days, everything costs 10 gold more. Create a rule marketDay with the type PriceRule, so that its parameter needs no type of its own: const marketDay: PriceRule = (price) => .... Then print priceTag("Lantern", 15, marketDay), which prints Lantern: 25 gold.

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

8/10