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:
Jessica Wilkins
2026-04-09 12:52:55 -07:00
committed by GitHub
parent 6ee501e857
commit 4bedfd797d
22 changed files with 1333 additions and 0 deletions
+6
View File
@@ -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": [
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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);
```
@@ -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
}
}
```
@@ -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);
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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);
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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
}
}
```
@@ -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",