Skip to content

Commit f624453

Browse files
committed
fix: address pedagogical issues in exercises
- Change 02.02 (Reassignment vs Mutation) from array to object mutation (arrays not yet introduced at this point in curriculum) - Change 03.03 (Null and Undefined) to use ternary operators instead of if statements (if statements taught later in 04.01) - Add callouts explaining built-in methods (Math.pow, Math.max, Math.min, Number(), throw, modulo operator) where they're used before formal introduction
1 parent 06ea32b commit f624453

File tree

36 files changed

+261
-580
lines changed

36 files changed

+261
-580
lines changed

exercises/02.variables/02.problem.reassignment-vs-mutation/README.mdx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,28 @@ x = 2 // x now points to a new value
1313
**Mutation**: Modifying the contents of an existing value
1414

1515
```ts
16-
const arr = [1, 2, 3]
17-
arr.push(4) // The array itself is modified (mutated)
16+
const obj = { count: 1 }
17+
obj.count = 2 // The object itself is modified (mutated)
1818
```
1919

2020
<callout-warning>
21-
`const` prevents reassignment but NOT mutation! You can still push to a
22-
`const` array or add properties to a `const` object.
21+
`const` prevents reassignment but NOT mutation! You can still change
22+
properties on a `const` object.
2323
</callout-warning>
2424

2525
🐨 Open <InlineFile file="index.ts" /> and:
2626

27-
1. Try to reassign the `const` array (see the error)
28-
2. Mutate the `const` array by adding an item
27+
1. Try to reassign the `const` object (see the error)
28+
2. Mutate the `const` object by changing its properties
2929
3. Observe that mutation works even with `const`
3030

31-
💰 Common array mutations:
31+
💰 Common object mutations:
3232

3333
```ts
34-
arr.push(item) // Add to end
35-
arr.pop() // Remove from end
36-
arr[0] = newValue // Replace at index
34+
obj.property = newValue // Change a property
35+
obj.newProp = value // Add a new property
3736
```
3837

39-
📜 [MDN - Array methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
38+
📜 [MDN - Working with Objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects)
4039

4140
🐨 Once you've completed the exercise, run `node index.ts` in the playground to test your work!
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
// Understanding Reassignment vs Mutation
22

3-
// This array is declared with const
4-
const shoppingList = ['milk', 'eggs', 'bread']
3+
// This object is declared with const
4+
const person = { name: 'Alice', age: 30, city: 'Seattle' }
55

6-
console.log('Original list:', shoppingList)
6+
console.log('Original person:', person)
77

8-
// 🐨 Try to reassign shoppingList to a new array:
9-
// shoppingList = ['apples', 'oranges']
8+
// 🐨 Try to reassign person to a new object:
9+
// person = { name: 'Bob', age: 25, city: 'Portland' }
1010
// 💣 Uncomment the line above and see the TypeScript error
1111

12-
// 🐨 Now try MUTATING the array by adding an item with push()
13-
// 💰 shoppingList.push('butter')
12+
// 🐨 Now try MUTATING the object by changing the age property
13+
// 💰 person.age = 31
1414

15-
// 🐨 Mutate again by changing the first item
16-
// 💰 shoppingList[0] = 'almond milk'
15+
// 🐨 Mutate again by changing the city
16+
// 💰 person.city = 'Portland'
1717

18-
console.log('Modified list:', shoppingList)
18+
console.log('Modified person:', person)
1919

2020
// 🦉 Key insight: const prevents reassignment, not mutation!
21-
// The variable shoppingList always points to the SAME array,
22-
// but the contents of that array can change.
21+
// The variable person always points to the SAME object,
22+
// but the properties of that object can change.
Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
11
import assert from 'node:assert/strict'
22
import { test } from 'node:test'
3-
import { shoppingList } from './index.ts'
3+
import { person } from './index.ts'
44

5-
await test('shoppingList should be mutated correctly', () => {
5+
await test('person object should be mutated correctly', () => {
66
assert.deepStrictEqual(
7-
shoppingList,
8-
['almond milk', 'eggs', 'bread', 'butter'],
9-
'🚨 shoppingList should contain ["almond milk", "eggs", "bread", "butter"] - use array methods like push() to add items',
10-
)
11-
assert.strictEqual(
12-
shoppingList.length,
13-
4,
14-
'🚨 shoppingList should have 4 items - make sure you added all the required items',
7+
person,
8+
{ name: 'Alice', age: 31, city: 'Portland' },
9+
'🚨 person should have age: 31 and city: "Portland" - mutate the object properties',
1510
)
1611
})
1712

18-
await test('first element should be "almond milk"', () => {
13+
await test('person age should be 31', () => {
1914
assert.strictEqual(
20-
shoppingList[0],
21-
'almond milk',
22-
'🚨 The first item should be "almond milk" - check the order you added items to the array',
15+
person.age,
16+
31,
17+
'🚨 person.age should be 31 - change the age property from 30 to 31',
2318
)
2419
})
2520

26-
await test('last element should be "butter"', () => {
21+
await test('person city should be Portland', () => {
2722
assert.strictEqual(
28-
shoppingList[shoppingList.length - 1],
29-
'butter',
30-
'🚨 The last item should be "butter" - make sure you added it as the final item',
23+
person.city,
24+
'Portland',
25+
'🚨 person.city should be "Portland" - change the city property',
3126
)
3227
})
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
// Understanding Reassignment vs Mutation
22

3-
// This array is declared with const
4-
const shoppingList = ['milk', 'eggs', 'bread']
3+
// This object is declared with const
4+
const person = { name: 'Alice', age: 30, city: 'Seattle' }
55

6-
console.log('Original list:', shoppingList)
6+
console.log('Original person:', person)
77

88
// ❌ This would cause an error - can't reassign a const
9-
// shoppingList = ['apples', 'oranges']
10-
// Error: Cannot assign to 'shoppingList' because it is a constant
9+
// person = { name: 'Bob', age: 25, city: 'Portland' }
10+
// Error: Cannot assign to 'person' because it is a constant
1111

12-
// ✅ But we CAN mutate the array
13-
shoppingList.push('butter')
12+
// ✅ But we CAN mutate the object
13+
person.age = 31
1414

15-
// ✅ And we can modify elements
16-
shoppingList[0] = 'almond milk'
15+
// ✅ And we can modify other properties
16+
person.city = 'Portland'
1717

18-
console.log('Modified list:', shoppingList)
19-
// Output: ['almond milk', 'eggs', 'bread', 'butter']
18+
console.log('Modified person:', person)
19+
// Output: { name: 'Alice', age: 31, city: 'Portland' }
2020

2121
// 🦉 Key insight: const prevents reassignment, not mutation!
22-
// The variable shoppingList always points to the SAME array,
23-
// but the contents of that array can change.
22+
// The variable person always points to the SAME object,
23+
// but the properties of that object can change.
2424

25-
export { shoppingList }
25+
export { person }

exercises/03.primitive-types/03.problem.null-and-undefined/README.mdx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,32 @@ The difference:
1010
- **`null`** - The value was intentionally set to "nothing"
1111

1212
```ts
13-
let middleName: string | undefined // might not exist
14-
const deletedAt: Date | null = null // intentionally empty
13+
let middleName = undefined // not set yet
14+
const deletedAt = null // intentionally empty
1515
```
1616

17-
🐨 Open <InlineFile file="index.ts" /> and:
18-
19-
1. Create a variable `discountCode` that can be `string` or `undefined`
20-
2. Create a variable `lastPurchaseDate` that can be `string` or `null`, set to
21-
`null`
22-
3. Check if `discountCode` has a value and log an appropriate message
23-
4. Handle the case where `lastPurchaseDate` is `null`
17+
## Ternary Operator
2418

25-
💰 Use union types with the pipe `|`:
19+
The ternary operator is a concise way to choose between two values based on a
20+
condition:
2621

2722
```ts
28-
let value: string | null = null
23+
const result = condition ? valueIfTrue : valueIfFalse
2924
```
3025

31-
💰 Check for null/undefined:
26+
🐨 Open <InlineFile file="index.ts" /> and:
27+
28+
1. Create a variable `discountCode` set to `undefined`
29+
2. Create a variable `lastPurchaseDate` set to `null`
30+
3. Use the ternary operator to log whether `discountCode` has a value
31+
4. Use the ternary operator to handle `lastPurchaseDate` being `null`
32+
33+
💰 Check for null/undefined with ternary:
3234

3335
```ts
34-
if (value !== undefined) {
35-
// value is definitely defined here
36-
}
36+
console.log(value !== undefined ? 'Has value: ' + value : 'No value')
3737
```
3838

39-
📜 [TypeScript Handbook - Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)
39+
📜 [TypeScript Handbook - Null and Undefined](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#null-and-undefined)
4040

4141
🐨 Once you've completed the exercise, run `node index.ts` in the playground to test your work!
Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
// Handling Missing Data
22
// Working with null and undefined
33

4-
// 🐨 Create a variable `discountCode` of type `string | undefined`
5-
// Leave it unassigned (it will be undefined)
4+
// 🐨 Create a variable `discountCode` set to undefined
65

7-
// 🐨 Create a variable `lastPurchaseDate` of type `string | null`
8-
// Set it to null (intentionally no purchase yet)
6+
// 🐨 Create a variable `lastPurchaseDate` set to null
97

10-
// 🐨 Check if discountCode has a value
11-
// If it does, log "Discount code: [code]"
12-
// If not, log "No discount code available"
13-
// 💰 Use: if (discountCode !== undefined)
8+
// 🐨 Log whether discountCode has a value using a ternary operator
9+
// 💰 console.log(discountCode !== undefined ? 'Discount code: ' + discountCode : 'No discount code available')
1410

15-
// 🐨 Check if lastPurchaseDate has a value
16-
// If it does, log "Last purchase: [date]"
17-
// If not, log "No previous purchases"
18-
// 💰 Use: if (lastPurchaseDate !== null)
11+
// 🐨 Log whether lastPurchaseDate has a value using a ternary operator
12+
// 💰 console.log(lastPurchaseDate !== null ? 'Last purchase: ' + lastPurchaseDate : 'No previous purchases')

exercises/03.primitive-types/03.solution.null-and-undefined/README.mdx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@
33
👨‍💼 You've handled missing data safely! This is a crucial skill in real-world
44
applications.
55

6-
🦉 The key insight is **narrowing**. When you check for `null` or `undefined`,
7-
TypeScript knows the type is more specific inside that block:
6+
🦉 The key insight: `null` and `undefined` represent two different kinds of
7+
"missing" values. You can check for each directly to decide what to do.
88

99
```ts
10-
let value: string | undefined
10+
const value = undefined
1111

12-
if (value !== undefined) {
13-
// TypeScript knows value is `string` here, not `string | undefined`
14-
console.log(value.toUpperCase()) // ✅ Safe!
12+
if (value === undefined) {
13+
console.log('Missing value')
1514
}
1615
```
1716

18-
This is one of TypeScript's superpowers—it tracks what you've checked and
19-
updates its understanding of types accordingly.
20-
2117
In practice, many developers prefer `null` for intentional absence (like "user
2218
hasn't set this yet") and let `undefined` represent truly missing values.
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
// Handling Missing Data
22
// Working with null and undefined
33

4-
let discountCode: string | undefined
4+
const discountCode = undefined
55

6-
const lastPurchaseDate: string | null = null
6+
const lastPurchaseDate = null
77

8-
if (discountCode !== undefined) {
9-
console.log(`Discount code: ${discountCode}`)
10-
} else {
11-
console.log('No discount code available')
12-
}
8+
// Using ternary operators to check for values
9+
console.log(
10+
discountCode !== undefined
11+
? 'Discount code: ' + discountCode
12+
: 'No discount code available',
13+
)
1314

14-
if (lastPurchaseDate !== null) {
15-
console.log(`Last purchase: ${lastPurchaseDate}`)
16-
} else {
17-
console.log('No previous purchases')
18-
}
15+
console.log(
16+
lastPurchaseDate !== null
17+
? 'Last purchase: ' + lastPurchaseDate
18+
: 'No previous purchases',
19+
)
1920

2021
export { discountCode, lastPurchaseDate }

exercises/04.control-flow/02.problem.loops/index.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

exercises/04.control-flow/03.problem.for-of-iteration/index.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)