Functions page
Learn how to annotate functions parameters and return values, use different parameter types available.
Overview
In this part, we will:
- Annotate functions parameters and return values.
- Use optional parameters & rest parameters
The exercise will have you update a function with TypeScript annotations.
Functions in TypeScript
In TypeScript, we're able to annotate function parameters to better guard our code. If the following, add
is called with two parameters that are not numbers TypeScript's compiler will throw an error when compiled.
function add(x: number, y: number): number {
return x + y;
}
add(1, 'three');
//Argument of type 'string' is not assignable to parameter of type 'number'.
We can also annotate what a function should return.
function returnNumber(): number {
return '1';
}
//Type 'string' is not assignable to type 'number'.
function returnNumber(): number {
return 1;
}
//works!
Optional Parameters
Sometimes when writing functions, we don't need every parameter to be satisfied. TypeScript allows us to mark optional parameters (or properties) with a ?
so the compiler will not error if an optional param isn't passed.
function buildDinosaur(name: string, breed: string, teeth?: number): void {
if (teeth) {
console.log(`${name} is a ${breed} and has ${teeth} teeth.`);
}
else {
console.log(`${name} is a ${breed}.`);
}
}
let newDino = buildDinosaur('Blue', 'Velociraptor', 80);
//works
let otherDino = buildDinosaur('Delta', 'Velociraptor');
//also works
let otherOtherDino = buildDinosaur('Charlie');
//error an argument for 'breed' was not provided
Rest Parameters
Rest parameters are a way to pass in an unknown number of arguments to a function. Rest params are signaled to the transpiler by passing an ellipsis (...) followed by the parameter name.
function buildDinosaur(breed: string, ...dna: string[]): void {
console.log(`The ${breed} has dna from ${dna.join(', ')}`)
}
buildDinosaur('Indominous Rex', 'Velociraptor', 'Tyrannosaurus rex', 'Therizinosaurus', 'cuttlefish');
//logs "The Indominous Rex has dna from Velociraptor,
// Tyrannosaurus rex, Therizinosaurus, cuttlefish"
this
Parameters
JavaScript functions can be called or created with a dynamic this
. For example:
const dog = {
name: 'fido',
bark: function() {
console.log(this.name + 'says woof');
}
};
const address = {street: '2 State St'};
dog.bark.call(dog); //logs "fido says woof";
dog.bark.call(address); //logs "undefined says woof"
Compiling with the --strictBindCallApply
flag allows you to
specify the this
type:
const dog = {
name: 'fido',
bark: function(this: {name: string}) {
console.log(this.name, 'says woof');
}
};
const address = {street: '2 State St'};
dog.bark.call(dog);
dog.bark.call(address);
Line 10 will error with: Property 'name' is missing in type '{ street: string; }' but required in type '{ name: string; }'.
Exercise: dnaCost
The Problem
The following function in 3-functions-dnaCost.ts
calculates the cost of synthesizing
a DNA sequence to make a dinosaur. It calculates the cost by adding a baseCost
plus
the length of the DNA sequence:
function dnaCost(baseCost, sequence) {
return baseCost + sequence.length;
}
let raptorCost = dnaCost(5000,"CGGCA");
console.log(raptorCost);
//Logs 5005
Now scientists want to mix the DNA of multiple dinosaurs.
Open the 3-functions-dnaCost.ts
file and modify this function to:
- take an unknown amount of sequences;
- return the sum of baseCost and the length of each sequence.
let raptorDNA = 'CGGCA';
let cuttlefishDNA = 'GATTACA';
let viperDNA = 'ATTAC';
let indoraptorCost = dnaCost(5000,raptorDNA, cuttlefishDNA, viperDNA);
console.log(indoraptorCost);
// Logs 5017
Verify Your Solution
✏️ Run the following to verify your solution:
npm run 3-functions
The Solution
Click to see the solution
✏️ Update 3-functions-dnaCost.ts
to add each sequence to the
base cost. This solution uses Array.prototype.reduce:
export function dnaCost(baseCost:number, ...sequences: string[]) {
return sequences.reduce(
(sum, sequence)=> sum + sequence.length,
baseCost );
}
You'll notice that specifying a return type is not necessary. This is because TypeScript can infer the return value from the arguments.
The following is another valid solution:
export function dnaCost(baseCost: number, ...sequences: string[]) {
let sum = baseCost;
sequences.forEach(sequence => sum += sequence.length);
return sum
}