Skip to content

Commit 2ad6e44

Browse files
jdwilkin4SembaukeDario-DCKsound22
authored
feat(curriculum): Add type safe user profile to typescript module (freeCodeCamp#66005)
Co-authored-by: Sem Bauke <sem@freecodecamp.org> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Kolade <chrisjay967@gmail.com>
1 parent 0e8da83 commit 2ad6e44

16 files changed

Lines changed: 877 additions & 0 deletions

client/i18n/locales/english/intro.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6181,6 +6181,12 @@
61816181
"In these lessons, you will learn what TypeScript is and how to use it."
61826182
]
61836183
},
6184+
"workshop-type-safe-user-profile": {
6185+
"title": "Build a Type Safe User Profile",
6186+
"intro": [
6187+
"In this workshop, you will practice working with type annotations, array types, object types and more by building out a user profile."
6188+
]
6189+
},
61846190
"lecture-understanding-type-composition": {
61856191
"title": "Understanding Type Composition",
61866192
"intro": [
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
id: 699b4e284291adcfcb90df47
3+
title: Step 1
4+
challengeType: 1
5+
dashedName: step-1
6+
---
7+
8+
# --description--
9+
10+
In this workshop, you will practice working with primitive types as well as object and array types by building out a type safe user profile.
11+
12+
Start by creating a variable called `profile` and assign it an object. Your object should have these three properties and values:
13+
14+
```md
15+
username: "codeLearner",
16+
age: 25,
17+
isLoggedIn: false,
18+
```
19+
20+
# --hints--
21+
22+
You should have a variable called `profile`.
23+
24+
```js
25+
assert.exists(profile);
26+
```
27+
28+
Your `profile` variable should be an object.
29+
30+
```js
31+
assert.isObject(profile);
32+
```
33+
34+
You should have a `username` property in your `profile` object.
35+
36+
```js
37+
assert.property(profile, "username");
38+
```
39+
40+
Your `username` property should have a value of `"codeLearner"`.
41+
42+
```js
43+
assert.propertyVal(profile, "username", "codeLearner");
44+
```
45+
46+
Your `profile` object should have an `age` property.
47+
48+
```js
49+
assert.property(profile, "age");
50+
```
51+
52+
Your `age` property should have a value of `25`.
53+
54+
```js
55+
assert.propertyVal(profile, "age", 25);
56+
```
57+
58+
Your `profile` object should have an `isLoggedIn` property.
59+
60+
```js
61+
assert.property(profile, "isLoggedIn");
62+
```
63+
64+
Your `isLoggedIn` property should have a value of `false`.
65+
66+
```js
67+
assert.propertyVal(profile, "isLoggedIn", false);
68+
```
69+
70+
# --seed--
71+
72+
## --seed-contents--
73+
74+
```ts
75+
--fcc-editable-region--
76+
77+
--fcc-editable-region--
78+
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
id: 699b5370a43e299b4673bcaa
3+
title: Step 2
4+
challengeType: 1
5+
dashedName: step-2
6+
---
7+
8+
# --description--
9+
10+
It would be helpful to see the `profile` object properties in the console as you build it out.
11+
12+
Add a `console.log` that logs `profile` to the console.
13+
14+
# --before-each--
15+
16+
```js
17+
const spy = __helpers.spyOn(console, 'log');
18+
const getLogs = () => spy.calls.map(call => call?.[0]);
19+
```
20+
21+
# --hints--
22+
23+
You should log `profile` to the console.
24+
25+
```js
26+
assert.equal(getLogs()[0], profile);
27+
```
28+
29+
# --seed--
30+
31+
## --seed-contents--
32+
33+
```ts
34+
const profile = {
35+
username: "codeLearner",
36+
age: 25,
37+
isLoggedIn: false,
38+
}
39+
40+
--fcc-editable-region--
41+
42+
--fcc-editable-region--
43+
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
id: 699b58c5abecfda9dc81c4ec
3+
title: Step 3
4+
challengeType: 1
5+
dashedName: step-3
6+
---
7+
8+
# --description--
9+
10+
Right now the `profile` object only has three properties. But it would be nice to have a few more.
11+
12+
Add a property called `mood` to the `profile` object. Its value should be `null`.
13+
14+
# --hints--
15+
16+
Your `profile` object should have a `mood` property.
17+
18+
```js
19+
assert.property(profile, "mood");
20+
```
21+
22+
Your `mood` property should have a value of `null`.
23+
24+
```js
25+
assert.isNull(profile?.mood);
26+
```
27+
28+
# --seed--
29+
30+
## --seed-contents--
31+
32+
```ts
33+
--fcc-editable-region--
34+
const profile = {
35+
username: "codeLearner",
36+
age: 25,
37+
isLoggedIn: false,
38+
39+
}
40+
--fcc-editable-region--
41+
42+
console.log(profile);
43+
```
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
id: 699b5b7cb68b6d35afca61b7
3+
title: Step 4
4+
challengeType: 1
5+
dashedName: step-4
6+
---
7+
8+
# --description--
9+
10+
While it is possible to continue to add properties like this to the `profile` object, it would be nice to restrict the types of properties that should be allowed. It would be better to define the shape of the `profile` object beforehand.
11+
12+
In prior lessons, you learned how to work with object types like this:
13+
14+
```ts
15+
const composer: {
16+
name: string;
17+
instrument: string;
18+
isActive: boolean;
19+
} = {
20+
name: "Ludwig van Beethoven",
21+
instrument: "Piano",
22+
isActive: false
23+
};
24+
```
25+
26+
In this example, `composer` is an object with an inline object type. This object has three required properties of `name`, `instrument` and `isActive`. The first two properties must be of type `string` and `isActive` must be of type `boolean`.
27+
28+
Update your existing `profile` object to include an inline object type. `username` should be typed to a `string`, `age` should be typed to a `number` and `isLoggedIn` should be typed to a `boolean`.
29+
30+
# --hints--
31+
32+
Your `profile` object should have an inline object type with a `username` property set to `string`.
33+
34+
```js
35+
const explorer = await __helpers.Explorer(code);
36+
const { profile } = explorer.variables;
37+
const prop = { name: "username", type: "string" };
38+
assert.isTrue(profile.annotation.hasTypeProps(prop));
39+
```
40+
41+
Your `profile` object should have an inline object type with an `age` property set to `number`.
42+
43+
```js
44+
const explorer = await __helpers.Explorer(code);
45+
const { profile } = explorer.variables;
46+
const prop = { name: "age", type: "number" };
47+
assert.isTrue(profile.annotation.hasTypeProps(prop));
48+
```
49+
50+
Your `profile` object should have an inline object type with an `isLoggedIn` property set to `boolean`.
51+
52+
```js
53+
const explorer = await __helpers.Explorer(code);
54+
const { profile } = explorer.variables;
55+
const prop = { name: "isLoggedIn", type: "boolean" };
56+
assert.isTrue(profile.annotation.hasTypeProps(prop));
57+
```
58+
59+
# --seed--
60+
61+
## --seed-contents--
62+
63+
```ts
64+
--fcc-editable-region--
65+
const profile = {
66+
username: "codeLearner",
67+
age: 25,
68+
isLoggedIn: false,
69+
mood: null
70+
}
71+
--fcc-editable-region--
72+
73+
console.log(profile);
74+
```
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
id: 699b61ca8c9cb9bc1968364e
3+
title: Step 5
4+
challengeType: 1
5+
dashedName: step-5
6+
---
7+
8+
# --description--
9+
10+
If you open up the console, you should see the following error message:
11+
12+
```md
13+
Object literal may only specify known properties, and 'mood' does not exist in type '{ username: string; age: number; isLoggedIn: boolean; }'.
14+
```
15+
16+
In vanilla JavaScript, you were allowed to add whatever properties and values you liked to the `profile` object. But in TypeScript, the compiler checks that the object only has the properties you defined (`username`, `age`, and `isLoggedIn` in this case). Since `mood` wasn't included in the type, TypeScript treats it as an invalid property and throws an error.
17+
18+
Remove the `mood: null` from your code.
19+
20+
# --hints--
21+
22+
You should no longer have `mood: null` in your code.
23+
24+
```js
25+
assert.isUndefined(profile.mood);
26+
```
27+
28+
# --seed--
29+
30+
## --seed-contents--
31+
32+
```ts
33+
const profile: {
34+
username: string;
35+
age: number;
36+
isLoggedIn: boolean;
37+
} = {
38+
username: "codeLearner",
39+
age: 25,
40+
isLoggedIn: false
41+
--fcc-editable-region--
42+
mood: null
43+
--fcc-editable-region--
44+
};
45+
46+
console.log(profile);
47+
```
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
id: 699b62c99ec8c63470313365
3+
title: Step 6
4+
challengeType: 1
5+
dashedName: step-6
6+
---
7+
8+
# --description--
9+
10+
Now it is time to add another property to your `profile` object.
11+
12+
Start by updating the inline object type to include a `bio` property with a type set to `string`.
13+
14+
# --hints--
15+
16+
You should update the inline object type to include a `bio` property set to `string`.
17+
18+
```js
19+
const explorer = await __helpers.Explorer(code);
20+
const { profile } = explorer.variables;
21+
const prop = { name: "bio", type: "string" };
22+
assert.isTrue(profile.annotation.hasTypeProps(prop));
23+
```
24+
25+
# --seed--
26+
27+
## --seed-contents--
28+
29+
```ts
30+
const profile: {
31+
--fcc-editable-region--
32+
username: string;
33+
age: number;
34+
isLoggedIn: boolean;
35+
36+
--fcc-editable-region--
37+
} = {
38+
username: "codeLearner",
39+
age: 25,
40+
isLoggedIn: false
41+
};
42+
43+
console.log(profile);
44+
```

0 commit comments

Comments
 (0)