mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add type safe math toolkit workshop to typescript module (#66073)
Co-authored-by: Kolade <chrisjay967@gmail.com> Co-authored-by: Kolade Chris <65571316+Ksound22@users.noreply.github.com>
This commit is contained in:
@@ -6187,6 +6187,12 @@
|
||||
"In this workshop, you will practice working with type annotations, array types, object types and more by building out a user profile."
|
||||
]
|
||||
},
|
||||
"workshop-type-safe-math-toolkit": {
|
||||
"title": "Build a Type Safe Math Toolkit",
|
||||
"intro": [
|
||||
"In this workshop, you will practice typing functions by building a math toolkit project."
|
||||
]
|
||||
},
|
||||
"lecture-understanding-type-composition": {
|
||||
"title": "Understanding Type Composition",
|
||||
"intro": [
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 699f1d72e906e4616155290d
|
||||
title: Step 1
|
||||
challengeType: 1
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you will continue to learn about type annotations and how they work with functions by building out a type safe math toolkit.
|
||||
|
||||
Start by creating a function called `square` that accepts a parameter and returns the square of a number.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a function called `square`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.allFunctions.square);
|
||||
```
|
||||
|
||||
Your `square` function should have one parameter.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.lengthOf(explorer.allFunctions.square.parameters, 1);
|
||||
```
|
||||
|
||||
Your `square` function should return the square of a number.
|
||||
|
||||
```js
|
||||
assert.strictEqual(square(2), 4);
|
||||
assert.strictEqual(square(3), 9);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 699f3738921fb79a651ded56
|
||||
title: Step 2
|
||||
challengeType: 1
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now it is time to call your function.
|
||||
|
||||
Create a variable called `result` and assign it the function call of `square` with an argument of `5`.
|
||||
|
||||
Below that, log the value of `result` to the console.
|
||||
|
||||
# --before-each--
|
||||
|
||||
```js
|
||||
const spy = __helpers.spyOn(console, 'log');
|
||||
const getLogs = () => spy.calls.map(call => call?.[0]);
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable called `result`.
|
||||
|
||||
```js
|
||||
assert.isDefined(result);
|
||||
```
|
||||
|
||||
Your `result` variable should be a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(result);
|
||||
```
|
||||
|
||||
Your `result` variable should be the square of `5`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(result, 25);
|
||||
```
|
||||
|
||||
You should log the `result` variable to the console.
|
||||
|
||||
```js
|
||||
assert.equal(getLogs()[0], result);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 699f38937b053e4679878ff1
|
||||
title: Step 3
|
||||
challengeType: 1
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When working with vanilla JavaScript, there is nothing to prevent you from calling the `square` function with a string or an array, which would lead to unexpected results.
|
||||
|
||||
To illustrate this, change your function call to use the string `"something"` instead of the number `5`.
|
||||
|
||||
In the next lesson, you will learn how to use TypeScript to add type safety to your code and prevent these kinds of errors.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `square` function call should have an argument of `"something"`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.variables.result.value.matches("square('something')"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const result = square(5);
|
||||
--fcc-editable-region--
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
---
|
||||
id: 699f3cb8d057f29954205d7d
|
||||
title: Step 4
|
||||
challengeType: 1
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As you recall from earlier lessons, you can add type annotations to function parameters like this:
|
||||
|
||||
```ts
|
||||
function add(num1: number, num2: number) {
|
||||
return num1 + num2;
|
||||
}
|
||||
```
|
||||
|
||||
In this example, TypeScript will display an error if you try to call the `add` function with arguments that are not numbers.
|
||||
|
||||
Update your `square` function to include a type annotation for the `num` parameter. The type should be `number`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a type annotation to the `num` parameter in the `square` function. The type should be a `number`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { parameters } = explorer.allFunctions.square;
|
||||
assert.isTrue(parameters[0].matches("num: number"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
--fcc-editable-region--
|
||||
function square(num) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const result = square("something");
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square("something");
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 699f3f636aa840b7201aa37c
|
||||
title: Step 5
|
||||
challengeType: 1
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you open up the console, you should see the following TypeScript error message:
|
||||
|
||||
```md
|
||||
Argument of type 'string' is not assignable to parameter of type 'number'
|
||||
```
|
||||
|
||||
Now that the parameter is explicitly typed as a number, TypeScript is able to catch the error of trying to pass a string argument to the `square` function.
|
||||
|
||||
Change the argument passed to the `square` function to the number `5` to fix the error and see the correct output in the console.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `square` function call should have an argument of `5` instead of `"something"`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(result, 25);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const result = square("something");
|
||||
--fcc-editable-region--
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 699f412114c87221f16a99e3
|
||||
title: Step 6
|
||||
challengeType: 1
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another benefit of using TypeScript is that it will catch errors if you pass to many or to few arguments to a function call.
|
||||
|
||||
To illustrate this, update your `square` function call to take two arguments of `5` and `10`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `square` function call should have two arguments of `5` and `10`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { result } = explorer.variables;
|
||||
assert.isTrue(result.value.matches("square(5, 10)"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const result = square(5);
|
||||
--fcc-editable-region--
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5, 10);
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
---
|
||||
id: 699f41b8da20f816b5c7dece
|
||||
title: Step 7
|
||||
challengeType: 1
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you open up the console, you should see the following error message:
|
||||
|
||||
```md
|
||||
Expected 1 arguments, but got 2.
|
||||
```
|
||||
|
||||
To resolve the error, update your `square` function call to take only one argument of `5`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `square` function call should have only one argument of `5`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(result, 25);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const result = square(5, 10);
|
||||
--fcc-editable-region--
|
||||
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 699f434e294a9e11cf4f65f0
|
||||
title: Step 8
|
||||
challengeType: 1
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now it is time to add another math helper to your toolkit project.
|
||||
|
||||
Start by creating a function called `getAverage` which takes one parameter. Your function should return the average for an array of numbers.
|
||||
|
||||
In the next few steps, you will add the type annotations for this function.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a function called `getAverage`.
|
||||
|
||||
```js
|
||||
assert.isFunction(getAverage);
|
||||
```
|
||||
|
||||
Your function should take one parameter.
|
||||
|
||||
```js
|
||||
assert.strictEqual(getAverage.length, 1);
|
||||
```
|
||||
|
||||
Your function should return a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(getAverage([1, 2, 3]));
|
||||
```
|
||||
|
||||
Your function should return the correct result for any array of numbers.
|
||||
|
||||
```js
|
||||
assert.strictEqual(getAverage([1, 2, 3, 4, 5]), 3);
|
||||
assert.strictEqual(getAverage([10, 20, 30]), 20);
|
||||
assert.strictEqual(getAverage([5, 10, 15, 20]), 12.5);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 699f458e47fb88c756fdba81
|
||||
title: Step 9
|
||||
challengeType: 1
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Right now, the `numbers` parameter has an implicit `any` type. To fix this, you can explicitly type the parameter as an array of numbers.
|
||||
|
||||
Recall from prior lessons, that you can type an array of numbers like this:
|
||||
|
||||
```ts
|
||||
const numbers: number[] = [1, 2, 3];
|
||||
```
|
||||
|
||||
Update your `getAverage` function to explicitly type the `numbers` parameter as an array of numbers.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `getAverage` function should have a parameter named `numbers` that is explicitly typed as an array of numbers.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const parameters = explorer.allFunctions.getAverage.parameters;
|
||||
assert.isTrue(parameters[0].matches("numbers: number[]"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
--fcc-editable-region--
|
||||
function getAverage(numbers) {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: 699f4639ae0016caaf81b7c6
|
||||
title: Step 10
|
||||
challengeType: 1
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now it is time to test out your function.
|
||||
|
||||
Start by creating a variable called `avgResult` and assigning it the function call of `getAverage`. The argument for that function call should be `[2, 14, 26, 8]`.
|
||||
|
||||
Then log the value of `avgResult` to the console.
|
||||
|
||||
# --before-each--
|
||||
|
||||
```js
|
||||
const spy = __helpers.spyOn(console, 'log');
|
||||
const getLogs = () => spy.calls.map(call => call?.[0]);
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable called `avgResult`.
|
||||
|
||||
```js
|
||||
assert.isDefined(avgResult);
|
||||
```
|
||||
|
||||
You should assign `getAverage([2, 14, 26, 8])` to your `avgResult` variable.
|
||||
|
||||
```js
|
||||
assert.strictEqual(avgResult, getAverage([2, 14, 26, 8]));
|
||||
```
|
||||
|
||||
Your `avgResult` variable should be a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(avgResult);
|
||||
```
|
||||
|
||||
You should log `avgResult` to the console.
|
||||
|
||||
```js
|
||||
assert.equal(getLogs()[1], avgResult);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]) {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 699f4861dd5b5f164e1bda4a
|
||||
title: Step 11
|
||||
challengeType: 1
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another benefit of using TypeScript is ensuring that the return types are enforced and what you expect. Sometimes TypeScript can infer the return type of a function, but you can also explicitly specify it.
|
||||
|
||||
To illustrate this, change the return type of the `getAverage` function to the string `"something"`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `getAverage` function should return a string.
|
||||
|
||||
```js
|
||||
assert.isString(getAverage([2, 14, 26, 8]));
|
||||
```
|
||||
|
||||
Your `getAverage` function should return the string `"something"`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(getAverage([2, 14, 26, 8]), "something");
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]) {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
--fcc-editable-region--
|
||||
return sum / numbers.length;
|
||||
--fcc-editable-region--
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
---
|
||||
id: 699f49669ea51a31d2ba89d8
|
||||
title: Step 12
|
||||
challengeType: 1
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As you recall from prior lessons, you can explicitly type the return type for a function like this:
|
||||
|
||||
```ts
|
||||
function circleArea(radius: number): number {
|
||||
return Math.PI * radius * radius;
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the return type of the `circleArea` function is `number`. If you try to return a different type, TypeScript will display an error.
|
||||
|
||||
Update your `getAverage` function to explicitly type the return type as `number`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `getAverage` function should have a return type of `number`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { getAverage } = explorer.allFunctions;
|
||||
assert.isTrue(getAverage.hasReturnAnnotation("number"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
--fcc-editable-region--
|
||||
function getAverage(numbers: number[]) {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return "something";
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return "something";
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 699f4a3e7b4c6bfa538cc4f7
|
||||
title: Step 13
|
||||
challengeType: 1
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you open up the console, you will see the following error message:
|
||||
|
||||
```md
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
```
|
||||
|
||||
To resolve this error, you need to change the return back to `sum / numbers.length`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `getAverage` function should return a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(getAverage([1, 2, 3]));
|
||||
```
|
||||
|
||||
Your `getAverage` function should return the average of the numbers in the array.
|
||||
|
||||
```js
|
||||
assert.strictEqual(getAverage([1, 2, 3]), 2);
|
||||
assert.strictEqual(getAverage([10, 20, 30]), 20);
|
||||
assert.strictEqual(getAverage([5, 10, 15, 20]), 12.5);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
--fcc-editable-region--
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return "something";
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
```
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
---
|
||||
id: 699f4b903bf5427a599f791d
|
||||
title: Step 14
|
||||
challengeType: 1
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In the last few steps, you will build out one more function to continue practicing type annotations with functions.
|
||||
|
||||
Start by creating a function called `raiseTo` which take two parameters called `base` and `exponent`. Both parameters should be of type `number`. The function should return the result of raising the `base` to the power of the `exponent`. The return type of the function should also be annotated as `number`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `raiseTo` function.
|
||||
|
||||
```js
|
||||
assert.isFunction(raiseTo);
|
||||
```
|
||||
|
||||
Your `raiseTo` function should have two parameters, `base` and `exponent`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
code,
|
||||
/function\s+raiseTo\s*\(\s*base\s*(?::\s*number)?\s*,\s*exponent\s*(?::\s*number)?\s*\)\s*|(?:const|let)\s+raiseTo\s*=\s*\(\s*base\s*(?::\s*number)?\s*,\s*exponent\s*(?::\s*number)?\s*\)\s*=>/
|
||||
);
|
||||
```
|
||||
|
||||
Your `base` and `exponent` parameters should both be of type `number`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { parameters } = explorer.allFunctions.raiseTo;
|
||||
assert.isTrue(parameters[0].matches("base: number"));
|
||||
assert.isTrue(parameters[1].matches("exponent: number"));
|
||||
```
|
||||
|
||||
Your `raiseTo` function should return a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(raiseTo(2, 3));
|
||||
```
|
||||
|
||||
Your `raiseTo` function should return the result of raising the `base` to the power of the `exponent`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(raiseTo(2, 3), 8);
|
||||
```
|
||||
|
||||
Your `raiseTo` function should have a return type annotation of `number`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { raiseTo } = explorer.allFunctions;
|
||||
assert.isTrue(raiseTo.hasReturnAnnotation("number"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
---
|
||||
id: 699f4ec939f10da62fb56c3e
|
||||
title: Step 15
|
||||
challengeType: 1
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now it is time to test out your function.
|
||||
|
||||
Create a variable called `raisedResult` and assign it the result of calling `raiseTo` with the arguments `2` and `3`.
|
||||
|
||||
Then, log `raisedResult` to the console.
|
||||
|
||||
# --before-each--
|
||||
|
||||
```js
|
||||
const spy = __helpers.spyOn(console, 'log');
|
||||
const getLogs = () => spy.calls.map(call => call?.[0]);
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable called `raisedResult`.
|
||||
|
||||
```js
|
||||
assert.isDefined(raisedResult);
|
||||
```
|
||||
|
||||
Your `raisedResult` variable should be a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(raisedResult);
|
||||
```
|
||||
|
||||
You should log `raisedResult` to the console.
|
||||
|
||||
```js
|
||||
assert.equal(getLogs()[2], raisedResult);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
function raiseTo(base: number, exponent: number): number {
|
||||
return base ** exponent;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: 699f5063d2393c674b1f45dc
|
||||
title: Step 16
|
||||
challengeType: 1
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As you recall from a prior step, if you call a function with the wrong number of arguments, TypeScript will throw and error.
|
||||
|
||||
There is a way to mark parameters as optional by adding a `?` after the parameter name. This allows you to call the function with fewer arguments than parameters.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```ts
|
||||
function greet(name: string, greeting?: string) {
|
||||
if (greeting) {
|
||||
return `${greeting}, ${name}!`;
|
||||
}
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
```
|
||||
|
||||
In this example, if the `greeting` parameter is not provided when calling the `greet` function, it will be `undefined`, and the function will return a default greeting.
|
||||
|
||||
Update your `raiseTo` function to make the `exponent` parameter optional.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `raiseTo` function should have the `exponent` parameter marked as optional.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
const { parameters } = explorer.allFunctions.raiseTo;
|
||||
assert.isTrue(parameters[1].matches("exponent?: number"));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
--fcc-editable-region--
|
||||
function raiseTo(base: number, exponent: number): number {
|
||||
return base ** exponent;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
const raisedResult = raiseTo(2, 3);
|
||||
console.log(raisedResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 699f513e01eb1768cc5df726
|
||||
title: Step 17
|
||||
challengeType: 1
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `exponent` parameter is marked as optional, you can call the function with just one argument.
|
||||
|
||||
Update your `raiseTo` function call to only pass in the number `3`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `raiseTo` function should be called with only one argument of `3`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
code,
|
||||
/raiseTo\s*\(\s*3\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
function raiseTo(base: number, exponent?: number): number {
|
||||
return base ** exponent;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
const raisedResult = raiseTo(2, 3);
|
||||
--fcc-editable-region--
|
||||
console.log(raisedResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 699f52220de88c8091032076
|
||||
title: Step 18
|
||||
challengeType: 1
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you open up the console, the result is `NaN` because the second argument for the `exponent` was never provided. There are a couple of updates needed for this `raiseTo` function that will fix this.
|
||||
|
||||
The first change is to return `base ** 2`.
|
||||
|
||||
In the next step, you will see how to handle the optional `exponent` parameter.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `raiseTo` function should return a number.
|
||||
|
||||
```js
|
||||
assert.isNumber(raiseTo(4));
|
||||
```
|
||||
|
||||
Your `raiseTo` function should return the value of `base` raised to the power of `2`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(raiseTo(4), 16);
|
||||
assert.strictEqual(raiseTo(5), 25);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
--fcc-editable-region--
|
||||
function raiseTo(base: number, exponent?: number): number {
|
||||
return base ** exponent;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
const raisedResult = raiseTo(3);
|
||||
console.log(raisedResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
---
|
||||
id: 699f52fac083214b6bf51de6
|
||||
title: Step 19
|
||||
challengeType: 1
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this last step, you will need to add a conditional check for the `exponent` parameter in the `raiseTo` function.
|
||||
|
||||
If the `exponent` argument is provided, the function should return `base` raised to the power of `exponent`. If the `exponent` argument is not provided, it should return `base ** 2`.
|
||||
|
||||
With that last step, your type-safe math toolkit is complete!
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `raiseTo` function should return `base ** exponent` when `exponent` argument is provided.
|
||||
|
||||
```js
|
||||
assert.strictEqual(raiseTo(3, 3), 27);
|
||||
```
|
||||
|
||||
Your `raiseTo` function should return `base ** 2` when `exponent` argument is not provided.
|
||||
|
||||
```js
|
||||
assert.strictEqual(raiseTo(3), 9);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
--fcc-editable-region--
|
||||
function raiseTo(base: number, exponent?: number): number {
|
||||
|
||||
return base ** 2;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
const raisedResult = raiseTo(3);
|
||||
console.log(raisedResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```ts
|
||||
function square(num: number) {
|
||||
return num * num;
|
||||
}
|
||||
|
||||
const result = square(5);
|
||||
|
||||
console.log(result);
|
||||
|
||||
function getAverage(numbers: number[]): number {
|
||||
const sum = numbers.reduce((acc, n) => acc + n, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
|
||||
const avgResult = getAverage([2, 14, 26, 8]);
|
||||
|
||||
console.log(avgResult);
|
||||
|
||||
function raiseTo(base: number, exponent?: number): number {
|
||||
if (exponent) {
|
||||
return base ** exponent;
|
||||
}
|
||||
|
||||
return base ** 2;
|
||||
}
|
||||
|
||||
const raisedResult = raiseTo(3);
|
||||
console.log(raisedResult);
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"isUpcomingChange": true,
|
||||
"dashedName": "workshop-type-safe-math-toolkit",
|
||||
"helpCategory": "JavaScript",
|
||||
"blockLayout": "challenge-grid",
|
||||
"challengeOrder": [
|
||||
{ "id": "699f1d72e906e4616155290d", "title": "Step 1" },
|
||||
{ "id": "699f3738921fb79a651ded56", "title": "Step 2" },
|
||||
{ "id": "699f38937b053e4679878ff1", "title": "Step 3" },
|
||||
{ "id": "699f3cb8d057f29954205d7d", "title": "Step 4" },
|
||||
{ "id": "699f3f636aa840b7201aa37c", "title": "Step 5" },
|
||||
{ "id": "699f412114c87221f16a99e3", "title": "Step 6" },
|
||||
{ "id": "699f41b8da20f816b5c7dece", "title": "Step 7" },
|
||||
{ "id": "699f434e294a9e11cf4f65f0", "title": "Step 8" },
|
||||
{ "id": "699f458e47fb88c756fdba81", "title": "Step 9" },
|
||||
{ "id": "699f4639ae0016caaf81b7c6", "title": "Step 10" },
|
||||
{ "id": "699f4861dd5b5f164e1bda4a", "title": "Step 11" },
|
||||
{ "id": "699f49669ea51a31d2ba89d8", "title": "Step 12" },
|
||||
{ "id": "699f4a3e7b4c6bfa538cc4f7", "title": "Step 13" },
|
||||
{ "id": "699f4b903bf5427a599f791d", "title": "Step 14" },
|
||||
{ "id": "699f4ec939f10da62fb56c3e", "title": "Step 15" },
|
||||
{ "id": "699f5063d2393c674b1f45dc", "title": "Step 16" },
|
||||
{ "id": "699f513e01eb1768cc5df726", "title": "Step 17" },
|
||||
{ "id": "699f52220de88c8091032076", "title": "Step 18" },
|
||||
{ "id": "699f52fac083214b6bf51de6", "title": "Step 19" }
|
||||
],
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
}
|
||||
@@ -92,6 +92,7 @@
|
||||
"blocks": [
|
||||
"lecture-introduction-to-typescript",
|
||||
"workshop-type-safe-user-profile",
|
||||
"workshop-type-safe-math-toolkit",
|
||||
"lecture-understanding-type-composition",
|
||||
"lecture-working-with-generics-and-type-narrowing",
|
||||
"lecture-working-with-typescript-configuration-files",
|
||||
|
||||
Reference in New Issue
Block a user