From 980912115d1b83b3ecbfeb5ad9e4c062a42942a3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Jul 2026 18:19:19 +0000 Subject: [PATCH] Clarify exercise requirements --- .../01.problem.hello-world/README.mdx | 12 +++- .../01.problem.hello-world/index.ts | 4 +- .../02.problem.escaping-strings/README.mdx | 23 +++++-- .../02.problem.escaping-strings/index.ts | 8 +-- .../03.problem.strings/README.mdx | 16 +++-- .../03.problem.strings/index.ts | 4 +- .../03.solution.strings/index.test.ts | 2 +- .../04.problem.numbers/README.mdx | 18 ++++-- .../04.problem.numbers/index.ts | 4 +- .../05.problem.template-literals/README.mdx | 19 +++++- .../05.problem.template-literals/index.ts | 7 ++- .../index.test.ts | 4 +- .../01.problem.let-and-const/README.mdx | 30 ++++++++-- .../01.problem.let-and-const/index.ts | 16 ++--- .../01.solution.let-and-const/index.test.ts | 4 +- .../README.mdx | 29 +++++++-- .../index.ts | 2 +- .../01.problem.numbers-and-strings/README.mdx | 23 +++++-- .../01.problem.numbers-and-strings/index.ts | 4 +- .../02.problem.comparisons/README.mdx | 33 ++++++++-- .../02.problem.comparisons/index.ts | 18 +++--- .../README.mdx | 38 ++++++++---- .../index.ts | 2 +- .../index.test.ts | 12 ++-- .../04.problem.null-and-undefined/README.mdx | 17 +++++- .../04.problem.null-and-undefined/index.ts | 2 +- .../05.problem.bigint-and-symbol/README.mdx | 23 ++++++- .../05.problem.bigint-and-symbol/index.ts | 7 +-- .../index.test.ts | 4 +- .../06.problem.truthy-falsy/README.mdx | 44 ++++++++++---- .../06.problem.truthy-falsy/index.ts | 14 ++--- .../06.solution.truthy-falsy/index.test.ts | 8 +-- .../01.problem.conditionals/README.mdx | 27 ++++++--- .../01.problem.conditionals/index.ts | 4 +- .../02.problem.switch-statements/README.mdx | 31 ++++++---- .../02.problem.switch-statements/index.ts | 18 +++--- .../03.problem.loops/README.mdx | 20 ++++++- .../04.control-flow/03.problem.loops/index.ts | 6 +- .../04.problem.nested-loops/README.mdx | 26 ++++++-- .../04.problem.nested-loops/index.ts | 8 +-- .../05.problem.ternary-operator/README.mdx | 27 +++++++-- .../05.problem.ternary-operator/index.ts | 14 ++--- .../06.problem.errors/README.mdx | 35 +++++++++-- .../06.problem.errors/index.ts | 10 ++-- .../README.mdx | 16 ++++- .../01.problem.function-declaration/index.ts | 7 ++- .../02.problem.parameters/README.mdx | 31 +++++++--- .../02.problem.parameters/index.ts | 18 +++--- .../02.solution.parameters/index.test.ts | 16 ++--- .../03.problem.type-inference/README.mdx | 29 +++++++-- .../03.problem.type-inference/index.ts | 10 ++-- .../03.solution.type-inference/index.test.ts | 12 ++-- .../04.problem.arrow-functions/README.mdx | 29 ++++++++- .../04.problem.arrow-functions/index.ts | 13 ++-- .../04.solution.arrow-functions/index.test.ts | 4 +- .../05.functions/05.problem.jsdoc/README.mdx | 39 ++++++++++-- .../05.functions/05.problem.jsdoc/index.ts | 13 ++-- .../01.problem.void-functions/README.mdx | 22 +++++-- .../01.problem.void-functions/index.ts | 14 +++-- .../02.problem.never-type/README.mdx | 33 ++++++---- .../02.problem.never-type/index.ts | 20 +++---- .../02.solution.never-type/index.test.ts | 4 +- extra/muffin-shop-checkout/README.mdx | 59 +++++++++++------- extra/muffin-shop-checkout/index.ts | 31 ++++------ extra/muffin-shop-dashboard/README.mdx | 60 ++++++++++++++----- .../muffin-shop-dashboard/src/muffin-utils.ts | 47 ++++++--------- 66 files changed, 818 insertions(+), 386 deletions(-) diff --git a/exercises/01.expressions-and-output/01.problem.hello-world/README.mdx b/exercises/01.expressions-and-output/01.problem.hello-world/README.mdx index 4387aac..734eaae 100644 --- a/exercises/01.expressions-and-output/01.problem.hello-world/README.mdx +++ b/exercises/01.expressions-and-output/01.problem.hello-world/README.mdx @@ -9,8 +9,16 @@ is how you see the results of your code. 🐨 Open and complete the following tasks: -1. Use `console.log()` to print the string `"Hello, World!"` -2. Use `console.log()` to print your name as a string +1. Use `console.log()` to print the exact string `"Hello, World!"` (capital H, + capital W, comma, and exclamation mark) +2. Use `console.log()` to print your name as a string on a second line + +## Completion criteria + +When you run the program, the output should include: + +- A line containing `Hello, World!` +- At least one more non-empty line (your name) πŸ’° Strings are text values wrapped in quotes (single or double). diff --git a/exercises/01.expressions-and-output/01.problem.hello-world/index.ts b/exercises/01.expressions-and-output/01.problem.hello-world/index.ts index 0b265b5..57965e7 100644 --- a/exercises/01.expressions-and-output/01.problem.hello-world/index.ts +++ b/exercises/01.expressions-and-output/01.problem.hello-world/index.ts @@ -1,6 +1,6 @@ // Your First Program // Let's print some messages to the console! -// 🐨 Use console.log() to print "Hello, World!" +// 🐨 Use console.log() to print the exact string "Hello, World!" -// 🐨 Use console.log() to print your name (as a string) +// 🐨 Use console.log() to print your name (as a string) on a second line diff --git a/exercises/01.expressions-and-output/02.problem.escaping-strings/README.mdx b/exercises/01.expressions-and-output/02.problem.escaping-strings/README.mdx index 6f0e7ac..0f008e5 100644 --- a/exercises/01.expressions-and-output/02.problem.escaping-strings/README.mdx +++ b/exercises/01.expressions-and-output/02.problem.escaping-strings/README.mdx @@ -41,12 +41,23 @@ console.log('Name:\tKody') // Prints with a tab between 🐨 Open and complete the following tasks: -1. Log a string using single quotes that contains an apostrophe (like "It's - working!") -2. Log a string using double quotes that contains a quoted phrase (like: She - said "Hi") -3. Log "Hello" and "World" on separate lines using `\n` in a single string -4. Log tab-separated column headers: "Name:" "Age:" "City:" using `\t` +1. Log the exact string `It's working!` using a single-quoted string (escape the + apostrophe) +2. Log the exact string `She said "Hi"` using a double-quoted string (escape the + inner quotes) +3. In a single string, log `Hello` and `World` on separate lines (use a newline + escape) +4. Log the exact tab-separated headers: `Name:` then tab then `Age:` then tab + then `City:` + +## Completion criteria + +Your program output should include all four of these (exact text and whitespace): + +- `It's working!` +- `She said "Hi"` +- `Hello` and `World` separated by a newline in one log +- `Name:\tAge:\tCity:` (tabs between the labels) πŸ’° Use backslash escape sequences for quotes, newlines, and tabs. The table above is your reference. diff --git a/exercises/01.expressions-and-output/02.problem.escaping-strings/index.ts b/exercises/01.expressions-and-output/02.problem.escaping-strings/index.ts index 1553b6e..efd36e4 100644 --- a/exercises/01.expressions-and-output/02.problem.escaping-strings/index.ts +++ b/exercises/01.expressions-and-output/02.problem.escaping-strings/index.ts @@ -1,10 +1,10 @@ // Escaping Strings // Learn to include special characters in strings -// 🐨 Log "It's working!" using single quotes (you'll need to escape the apostrophe) +// 🐨 Log exactly: It's working! (single-quoted string; escape the apostrophe) -// 🐨 Log: She said "Hi" (using double quotes for the string) +// 🐨 Log exactly: She said "Hi" (double-quoted string; escape the inner quotes) -// 🐨 Log "Hello" and "World" on separate lines using a single string with \n +// 🐨 Log "Hello" and "World" on separate lines using a single string with a newline escape -// 🐨 Log tab-separated data: Name: [tab] Age: [tab] City: (like column headers) +// 🐨 Log exactly: Name: [tab] Age: [tab] City: diff --git a/exercises/01.expressions-and-output/03.problem.strings/README.mdx b/exercises/01.expressions-and-output/03.problem.strings/README.mdx index 2418727..7ecb16c 100644 --- a/exercises/01.expressions-and-output/03.problem.strings/README.mdx +++ b/exercises/01.expressions-and-output/03.problem.strings/README.mdx @@ -14,10 +14,18 @@ console.log('Hello' + ' ' + 'World') // Prints: Hello World 🐨 Open and complete the following tasks: -1. Log the result of concatenating `"Hello"` and `"TypeScript"` with a space - between them -2. Log your first name and last name concatenated together -3. Log a longer message by concatenating multiple strings +1. Concatenate the strings `"Hello"`, a space, and `"TypeScript"`, then log the + result (output must include `Hello TypeScript`) +2. Concatenate your first name, a space, and your last name, then log the result +3. Concatenate multiple small string pieces to produce exactly: + `I am learning to code` (include the spaces between words) + +## Completion criteria + +- Output includes `Hello TypeScript` +- Output includes `I am learning to code` +- Your source uses the `+` operator to concatenate string literals at least + three times (this step is about concatenation, not template literals) πŸ’° Remember to include spaces where you need them - the `+` operator joins strings exactly as they are! diff --git a/exercises/01.expressions-and-output/03.problem.strings/index.ts b/exercises/01.expressions-and-output/03.problem.strings/index.ts index 8f95cf4..4ab085b 100644 --- a/exercises/01.expressions-and-output/03.problem.strings/index.ts +++ b/exercises/01.expressions-and-output/03.problem.strings/index.ts @@ -1,9 +1,9 @@ // String Expressions // Learn to work with text data -// 🐨 Log "Hello" + " " + "TypeScript" (concatenate these three strings) +// 🐨 Log the concatenation of "Hello", a space, and "TypeScript" // 🐨 Log your first name and last name concatenated together with a space -// 🐨 Log a sentence by concatenating multiple strings +// 🐨 Log the sentence "I am learning to code" by concatenating multiple strings // πŸ’° Build the sentence from small pieces and include spaces where needed diff --git a/exercises/01.expressions-and-output/03.solution.strings/index.test.ts b/exercises/01.expressions-and-output/03.solution.strings/index.test.ts index 551b7d1..da02b23 100644 --- a/exercises/01.expressions-and-output/03.solution.strings/index.test.ts +++ b/exercises/01.expressions-and-output/03.solution.strings/index.test.ts @@ -27,7 +27,7 @@ const output = getOutput() await test('should print Hello TypeScript', () => { assert.ok( output.includes('Hello TypeScript'), - '🚨 Output should include "Hello TypeScript" - concatenate "Hello" + " " + "TypeScript"', + '🚨 Output should include "Hello TypeScript" - concatenate those three pieces with +', ) }) diff --git a/exercises/01.expressions-and-output/04.problem.numbers/README.mdx b/exercises/01.expressions-and-output/04.problem.numbers/README.mdx index 948ad42..b1f2738 100644 --- a/exercises/01.expressions-and-output/04.problem.numbers/README.mdx +++ b/exercises/01.expressions-and-output/04.problem.numbers/README.mdx @@ -25,10 +25,20 @@ a complete list in the 🐨 Open and complete the following tasks: -1. Log the result of adding 25 and 17 -2. Log the result of multiplying 8 by 6 -3. Log the result of dividing 100 by 4 -4. Log the result of a more complex expression: `(10 + 5) * 2` +1. Log the result of adding `25` and `17` +2. Log the result of multiplying `8` by `6` +3. Log the result of dividing `100` by `4` +4. Log the result of adding `10` and `5`, then multiplying that sum by `2` + (group the addition so it happens first) + +## Completion criteria + +Your output should include these numeric results (each on its own line is fine): + +- `42` (from 25 + 17) +- `48` (from 8 Γ— 6) +- `25` (from 100 Γ· 4) +- `30` (from (10 + 5) Γ— 2) πŸ’° You can use parentheses to control the order of operations, just like in regular math! diff --git a/exercises/01.expressions-and-output/04.problem.numbers/index.ts b/exercises/01.expressions-and-output/04.problem.numbers/index.ts index 1d7104f..4cde8be 100644 --- a/exercises/01.expressions-and-output/04.problem.numbers/index.ts +++ b/exercises/01.expressions-and-output/04.problem.numbers/index.ts @@ -7,5 +7,5 @@ // 🐨 Use console.log to show the result of 100 divided by 4 -// 🐨 Use console.log to show the result of (10 + 5) multiplied by 2 -// πŸ’° Use parentheses to control order of operations +// 🐨 Use console.log to show the result of adding 10 and 5, then multiplying by 2 +// πŸ’° Use parentheses so the addition happens before the multiplication diff --git a/exercises/01.expressions-and-output/05.problem.template-literals/README.mdx b/exercises/01.expressions-and-output/05.problem.template-literals/README.mdx index a1f6ecf..537a5bb 100644 --- a/exercises/01.expressions-and-output/05.problem.template-literals/README.mdx +++ b/exercises/01.expressions-and-output/05.problem.template-literals/README.mdx @@ -30,9 +30,22 @@ console.log(`Hello, ${'World'}!`) // Prints: Hello, World! 🐨 Open and complete the following tasks: -1. Log a template literal that says "The answer is 42" using `${40 + 2}` -2. Log a greeting that includes "Hello" and "TypeScript" in one template literal -3. Log a math problem and its answer, like "10 times 5 equals 50" +1. Log a template literal whose output is exactly `The answer is 42`, embedding a + calculation that evaluates to `42` (do not hardcode the digits `42` as plain + text alone) +2. Log a greeting template literal that includes both `Hello` and `TypeScript` + (for example: `Hello, TypeScript!`) +3. Log a math sentence whose output includes `50` as the computed answer (for + example: `10 times 5 equals 50`), embedding the multiplication in the + template + +## Completion criteria + +Your output should include: + +- `The answer is 42` +- Text containing both `Hello` and `TypeScript` (any casing is fine for the check) +- The number `50` as part of a logged math sentence πŸ’° The backtick key is usually in the top-left of your keyboard, below Escape. diff --git a/exercises/01.expressions-and-output/05.problem.template-literals/index.ts b/exercises/01.expressions-and-output/05.problem.template-literals/index.ts index 464b275..80b0946 100644 --- a/exercises/01.expressions-and-output/05.problem.template-literals/index.ts +++ b/exercises/01.expressions-and-output/05.problem.template-literals/index.ts @@ -1,8 +1,9 @@ // Template Literals // A better way to build strings -// 🐨 Log "The answer is 42" using a template literal with ${40 + 2} +// 🐨 Log "The answer is 42" using a template literal +// πŸ’° Embed a calculation that evaluates to 42 -// 🐨 Log "Hello, TypeScript!" using a template literal +// 🐨 Log a greeting that includes "Hello" and "TypeScript" using a template literal -// 🐨 Log a math problem like "10 times 5 equals 50" +// 🐨 Log a math sentence whose answer is 50 (embed the multiplication) diff --git a/exercises/01.expressions-and-output/05.solution.template-literals/index.test.ts b/exercises/01.expressions-and-output/05.solution.template-literals/index.test.ts index 7fcefb1..0baa3b0 100644 --- a/exercises/01.expressions-and-output/05.solution.template-literals/index.test.ts +++ b/exercises/01.expressions-and-output/05.solution.template-literals/index.test.ts @@ -26,7 +26,7 @@ const output = getOutput() await test('should print "The answer is 42"', () => { assert.ok( output.includes('The answer is 42'), - '🚨 Output should include "The answer is 42" - use a template literal with ${40 + 2}', + '🚨 Output should include "The answer is 42" - use a template literal and embed a calculation for 42', ) }) @@ -41,6 +41,6 @@ await test('should print Hello, TypeScript! greeting', () => { await test('should print math result with 50', () => { assert.ok( output.includes('50'), - '🚨 Output should include 50 (the result of 10 * 5) - use ${10 * 5} in a template literal', + '🚨 Output should include 50 as the computed answer in a template-literal math sentence', ) }) diff --git a/exercises/02.variables/01.problem.let-and-const/README.mdx b/exercises/02.variables/01.problem.let-and-const/README.mdx index 07e3ae0..c81fa31 100644 --- a/exercises/02.variables/01.problem.let-and-const/README.mdx +++ b/exercises/02.variables/01.problem.let-and-const/README.mdx @@ -8,11 +8,31 @@ product prices). 🐨 Open and: -1. Create a `const` for `TAX_RATE` set to `0.08` -2. Create a `let` for `cartTotal` starting at `0` -3. Create `const` variables for product prices: `bookPrice`, `muffinPrice`, and `laptopPrice` -4. Add items to the cart by updating `cartTotal` -5. Try to reassign `TAX_RATE` and see what TypeScript says +1. Create a `const` named `TAX_RATE` set to `0.08` +2. Create a `let` named `cartTotal` starting at `0` +3. Create `const` product prices with these exact values: + - `bookPrice` = `15.99` + - `muffinPrice` = `4.5` + - `laptopPrice` = `999.99` +4. Add the book and the muffin to the cart by updating `cartTotal` (do **not** + add the laptop for this step) +5. Create `finalTotal` as the cart subtotal plus 8% tax (`TAX_RATE`) +6. Try to reassign `TAX_RATE` (keep it commented after you see the TypeScript + error) and export your results + +## Required exports + +Export these names so the tests can verify your work: + +- `TAX_RATE` +- `cartTotal` +- `finalTotal` + +## Completion criteria (with the fixtures above) + +- `TAX_RATE` is `0.08` +- `cartTotal` is `20.49` (book + muffin only) +- `finalTotal` is `22.1292` (subtotal + 8% tax) πŸ’° By convention, constants that represent fixed values are often UPPER_CASE: diff --git a/exercises/02.variables/01.problem.let-and-const/index.ts b/exercises/02.variables/01.problem.let-and-const/index.ts index e05fb69..ae3ec63 100644 --- a/exercises/02.variables/01.problem.let-and-const/index.ts +++ b/exercises/02.variables/01.problem.let-and-const/index.ts @@ -6,18 +6,18 @@ // 🐨 Create a variable `cartTotal` using `let`, starting at 0 // 🐨 Create constants for product prices: -// - bookPrice is $15.99 -// - muffinPrice is $4.5 -// - laptopPrice is $999.99 -// πŸ’° note, TypeScript doesn't know/care about whether the number represents -// money, a count, or anything, so you don't use the dollar sign in this syntax +// - bookPrice is 15.99 +// - muffinPrice is 4.5 +// - laptopPrice is 999.99 +// πŸ’° TypeScript doesn't know/care whether the number represents money or a +// count, so you don't use a dollar sign in the syntax // 🐨 Add the book to the cart (update cartTotal) // 🐨 Add the muffin to the cart (update cartTotal) +// πŸ’° Leave the laptop out of the cart for this exercise -// 🐨 Calculate the final total with tax -// πŸ’° Include tax when computing the final total +// 🐨 Create `finalTotal` as cartTotal plus 8% tax using TAX_RATE // 🐨 Try uncommenting the line below - what happens? // TAX_RATE = 0.10 @@ -27,5 +27,5 @@ // console.log('Tax:', cartTotal * TAX_RATE) // console.log('Final total:', finalTotal) -// 🐨 Export your variables so we can verify your work +// 🐨 Export TAX_RATE, cartTotal, and finalTotal so we can verify your work // export { TAX_RATE, cartTotal, finalTotal } diff --git a/exercises/02.variables/01.solution.let-and-const/index.test.ts b/exercises/02.variables/01.solution.let-and-const/index.test.ts index 14cb84c..6a47dd5 100644 --- a/exercises/02.variables/01.solution.let-and-const/index.test.ts +++ b/exercises/02.variables/01.solution.let-and-const/index.test.ts @@ -28,7 +28,7 @@ await test('cartTotal should be calculated correctly', () => { // cartTotal = bookPrice + muffinPrice = 15.99 + 4.5 = 20.49 assert.ok( Math.abs(solution.cartTotal - 20.49) < Math.pow(10, -2), - '🚨 cartTotal should be 20.49 - add bookPrice and muffinPrice together', + '🚨 cartTotal should be 20.49 - add the book and muffin prices (not the laptop)', ) }) @@ -43,6 +43,6 @@ await test('finalTotal should include tax', () => { // finalTotal = cartTotal + cartTotal * TAX_RATE = 20.49 + 20.49 * 0.08 = 22.1292 assert.ok( Math.abs(solution.finalTotal - 22.1292) < Math.pow(10, -4), - '🚨 finalTotal should be 22.1292 - add the tax (cartTotal * TAX_RATE) to cartTotal', + '🚨 finalTotal should be 22.1292 - subtotal plus 8% tax', ) }) diff --git a/exercises/02.variables/02.problem.reassignment-vs-mutation/README.mdx b/exercises/02.variables/02.problem.reassignment-vs-mutation/README.mdx index 6c759b3..87ce42e 100644 --- a/exercises/02.variables/02.problem.reassignment-vs-mutation/README.mdx +++ b/exercises/02.variables/02.problem.reassignment-vs-mutation/README.mdx @@ -24,12 +24,31 @@ obj.count = 2 // The object itself is modified (mutated) properties on a `const` object. -🐨 Open and: +🐨 Open . The starter already declares: -1. Try to reassign the `const` object (see the error) -2. Mutate the `const` object by changing `age` to `31` and `city` to - `'Portland'` -3. Observe that mutation works even with `const` +```ts +const person = { name: 'Alice', age: 30, city: 'Seattle' } +``` + +Complete these tasks: + +1. Try to reassign `person` to a new object (uncomment the line and observe the + TypeScript error), then leave that reassignment commented out +2. Mutate `person` so `age` becomes `31` and `city` becomes `'Portland'` + (`name` stays `'Alice'`) +3. Export `person` + +## Required exports + +- `person` + +## Completion criteria + +After mutation, `person` must deep-equal: + +```ts +{ name: 'Alice', age: 31, city: 'Portland' } +``` πŸ’° Mutation means changing properties on the existing object (not replacing the object itself). diff --git a/exercises/02.variables/02.problem.reassignment-vs-mutation/index.ts b/exercises/02.variables/02.problem.reassignment-vs-mutation/index.ts index 54d7285..40b33bf 100644 --- a/exercises/02.variables/02.problem.reassignment-vs-mutation/index.ts +++ b/exercises/02.variables/02.problem.reassignment-vs-mutation/index.ts @@ -19,5 +19,5 @@ console.log('Modified person:', person) // The variable person always points to the SAME object, // but the properties of that object can change. -// 🐨 Export your variable so we can verify your work +// 🐨 Export person so we can verify your work // export { person } diff --git a/exercises/03.primitive-types/01.problem.numbers-and-strings/README.mdx b/exercises/03.primitive-types/01.problem.numbers-and-strings/README.mdx index 4d28c75..54c393a 100644 --- a/exercises/03.primitive-types/01.problem.numbers-and-strings/README.mdx +++ b/exercises/03.primitive-types/01.problem.numbers-and-strings/README.mdx @@ -13,11 +13,24 @@ We need to track: 🐨 Open and complete the following tasks: -1. Create a variable `price` with type `number` set to `29.99` -2. Create a variable `productName` with type `string` set to `"TypeScript Guide"` -3. Create a variable `quantity` with type `number` set to `100` -4. Create a `description` variable that uses a template literal to combine the - product info +1. Create `price` with type `number` set to `29.99` +2. Create `productName` with type `string` set to `"TypeScript Guide"` +3. Create `quantity` with type `number` set to `100` +4. Create `description` as a string (prefer a template literal) with this exact + value: + `Product: TypeScript Guide | Price: $29.99 | In Stock: 100` + +## Required exports + +Export: `price`, `productName`, `quantity`, `description` + +## Completion criteria + +- `price` is the number `29.99` +- `productName` is `"TypeScript Guide"` +- `quantity` is the number `100` +- `description` matches the exact formatted string above (including `$`, spaces, + and `|` separators) πŸ’° Template literals let you embed expressions inside a string. diff --git a/exercises/03.primitive-types/01.problem.numbers-and-strings/index.ts b/exercises/03.primitive-types/01.problem.numbers-and-strings/index.ts index a63f4d5..3bdf4d3 100644 --- a/exercises/03.primitive-types/01.problem.numbers-and-strings/index.ts +++ b/exercises/03.primitive-types/01.problem.numbers-and-strings/index.ts @@ -7,7 +7,7 @@ // 🐨 Create a variable `quantity` with type `number` set to 100 -// 🐨 Create a `description` using a template literal that outputs: +// 🐨 Create a `description` using a template literal that equals exactly: // "Product: TypeScript Guide | Price: $29.99 | In Stock: 100" // βœ… These console.logs will verify your work @@ -16,5 +16,5 @@ // console.log('Quantity:', quantity) // console.log('Description:', description) -// 🐨 Export your variables so we can verify your work +// 🐨 Export price, productName, quantity, and description // export { price, productName, quantity, description } diff --git a/exercises/03.primitive-types/02.problem.comparisons/README.mdx b/exercises/03.primitive-types/02.problem.comparisons/README.mdx index a1f8782..ff83aa4 100644 --- a/exercises/03.primitive-types/02.problem.comparisons/README.mdx +++ b/exercises/03.primitive-types/02.problem.comparisons/README.mdx @@ -46,11 +46,36 @@ a >= b // greater than or equal a <= b // less than or equal ``` -🐨 Open and: +🐨 Open . The starter provides: -1. Compare `price` (number) and `quantity` (string) with both `==` and `===` -2. Use `!=` and `!==` to check if `a` is not equal to `b` -3. Use `>` and `<=` to compare `a` and `b` +- `price: number = 100` +- `quantity: string = '100'` +- `a: number = 10` +- `b: number = 20` + +Create and export these variables: + +1. `looseEqual` β€” compare `price` and `quantity` with `==` +2. `strictEqual` β€” compare `price` and `quantity` with `===` +3. `notEqualLoose` β€” whether `a` is not equal to `b` using `!=` +4. `notEqualStrict` β€” whether `a` is not equal to `b` using `!==` +5. `isGreater` β€” whether `b` is greater than `a` +6. `isLessOrEqual` β€” whether `a` is less than or equal to `b` + +For the `price`/`quantity` comparisons, add a `// @ts-expect-error` comment on +the line above each comparison so TypeScript allows comparing different types +(that's part of the lesson). + +## Required exports + +`looseEqual`, `strictEqual`, `notEqualLoose`, `notEqualStrict`, `isGreater`, +`isLessOrEqual` + +## Completion criteria + +Each export is a boolean produced by the comparison described above. Log or +inspect the values with these fixtures so you can see how loose vs strict +equality (and the other operators) evaluateβ€”don't hardcode the answers. πŸ“œ [MDN - Equality comparisons](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) diff --git a/exercises/03.primitive-types/02.problem.comparisons/index.ts b/exercises/03.primitive-types/02.problem.comparisons/index.ts index c7c8879..5b9a443 100644 --- a/exercises/03.primitive-types/02.problem.comparisons/index.ts +++ b/exercises/03.primitive-types/02.problem.comparisons/index.ts @@ -4,11 +4,11 @@ const price: number = 100 const quantity: string = '100' -// 🐨 Create a variable `looseEqual` that compares price and quantity with == -// add a @ts-expect-error comment to suppress the TypeScript error (that's the point!) +// 🐨 Create `looseEqual` that compares price and quantity with == +// πŸ’° Add a @ts-expect-error comment above the comparison (TypeScript will warn) -// 🐨 Create a variable `strictEqual` that compares price and quantity with === -// add a @ts-expect-error comment to suppress the TypeScript error (that's the point!) +// 🐨 Create `strictEqual` that compares price and quantity with === +// πŸ’° Add a @ts-expect-error comment above the comparison // 🐨 Log both results to see the difference // console.log('Loose equality (==):', looseEqual) @@ -17,18 +17,18 @@ const quantity: string = '100' const a: number = 10 const b: number = 20 -// 🐨 Create a variable `notEqualLoose` using != to check if a is not equal to b +// 🐨 Create `notEqualLoose` using != to check if a is not equal to b -// 🐨 Create a variable `notEqualStrict` using !== to check if a is not equal to b +// 🐨 Create `notEqualStrict` using !== to check if a is not equal to b -// 🐨 Create a variable `isGreater` that checks if b is greater than a +// 🐨 Create `isGreater` that checks if b is greater than a -// 🐨 Create a variable `isLessOrEqual` that checks if a is less than or equal to b +// 🐨 Create `isLessOrEqual` that checks if a is less than or equal to b // console.log('a != b:', notEqualLoose) // console.log('a !== b:', notEqualStrict) // console.log('b > a:', isGreater) // console.log('a <= b:', isLessOrEqual) -// 🐨 Export your variables so we can verify your work +// 🐨 Export looseEqual, strictEqual, notEqualLoose, notEqualStrict, isGreater, isLessOrEqual // export { looseEqual, strictEqual, notEqualLoose, notEqualStrict, isGreater, isLessOrEqual } diff --git a/exercises/03.primitive-types/03.problem.booleans-and-comparisons/README.mdx b/exercises/03.primitive-types/03.problem.booleans-and-comparisons/README.mdx index 1314cf6..1901558 100644 --- a/exercises/03.primitive-types/03.problem.booleans-and-comparisons/README.mdx +++ b/exercises/03.primitive-types/03.problem.booleans-and-comparisons/README.mdx @@ -25,21 +25,35 @@ const result2 = a && (b || c) // || happens first, then && const result3 = (a || b) && c // || happens first, then && ``` -🐨 Open and complete the following tasks: +🐨 Open . The starter provides: -1. Create a variable `isAvailable` with type `boolean` set to `true` -2. Create a variable `hasDiscount` that's `true` when the price is under 50 -3. Create a variable `canPurchase` that's `true` when the item is available AND - in stock -4. Create a variable `isNotAvailable` that's the opposite of `isAvailable` using - the `!` operator +- `price: number = 29.99` +- `stockCount: number = 100` + +Complete the following tasks: + +1. Create `isAvailable` with type `boolean` set to `true` +2. Create `hasDiscount` that is `true` when `price` is under `50` +3. Create `canPurchase` that is `true` when `isAvailable` is true **and** + `stockCount` is greater than `0` +4. Create `isNotAvailable` that is the opposite of `isAvailable` + +After the variables exist, remove the `// @ts-expect-error` comments above the +`console.log` lines so the file typechecks cleanly. + +## Required exports + +`isAvailable`, `hasDiscount`, `canPurchase`, `isNotAvailable` + +## Completion criteria + +All four exports should be real booleans (`typeof` is `"boolean"`), not strings. +Use the fixtures and rules above to check your results (for example by logging). πŸ“œ [MDN - Logical operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#logical_operators) - You'll notice `// @ts-expect-error` comments in the code. This tells - TypeScript to ignore the type error on the next line. Once you've created the - variables (`isAvailable`, `isOnSale`, `hasDiscount`, `canPurchase`, - `isNotAvailable`), you can remove these comments and the code will work - correctly! + You'll notice `// @ts-expect-error` comments in the starter. Those suppress + errors for names that don't exist yet. Once you've created `isAvailable`, + `hasDiscount`, `canPurchase`, and `isNotAvailable`, remove those comments. diff --git a/exercises/03.primitive-types/03.problem.booleans-and-comparisons/index.ts b/exercises/03.primitive-types/03.problem.booleans-and-comparisons/index.ts index 745e585..e6b797a 100644 --- a/exercises/03.primitive-types/03.problem.booleans-and-comparisons/index.ts +++ b/exercises/03.primitive-types/03.problem.booleans-and-comparisons/index.ts @@ -22,5 +22,5 @@ console.log('Can Purchase:', canPurchase) // @ts-expect-error - πŸ’£ remove this comment console.log('Is Not Available:', isNotAvailable) -// 🐨 Export your variables so we can verify your work +// 🐨 Export isAvailable, hasDiscount, canPurchase, and isNotAvailable // export { isAvailable, hasDiscount, canPurchase, isNotAvailable } diff --git a/exercises/03.primitive-types/03.solution.booleans-and-comparisons/index.test.ts b/exercises/03.primitive-types/03.solution.booleans-and-comparisons/index.test.ts index 0eb67a4..f2ad282 100644 --- a/exercises/03.primitive-types/03.solution.booleans-and-comparisons/index.test.ts +++ b/exercises/03.primitive-types/03.solution.booleans-and-comparisons/index.test.ts @@ -33,7 +33,7 @@ await test('hasDiscount should be true (price < 50)', () => { assert.strictEqual( solution.hasDiscount, true, - '🚨 hasDiscount should be true when price < 50 - use a comparison: price < 50', + '🚨 hasDiscount should be true when price is under 50 - use a comparison against price', ) }) @@ -41,7 +41,7 @@ await test('hasDiscount should be a boolean type', () => { assert.strictEqual( typeof solution.hasDiscount, 'boolean', - '🚨 hasDiscount should be a boolean type - use a comparison: price < 50', + '🚨 hasDiscount should be a boolean type - compare price to 50', ) }) @@ -56,12 +56,12 @@ await test('canPurchase should be true (isAvailable && stockCount > 0)', () => { assert.strictEqual( solution.canPurchase, true, - '🚨 canPurchase should be true when both isAvailable is true AND stockCount > 0 - use the && operator', + '🚨 canPurchase should be true when the item is available and stockCount is greater than 0', ) assert.strictEqual( typeof solution.canPurchase, 'boolean', - '🚨 canPurchase should be a boolean type - use a logical expression that returns true or false', + '🚨 canPurchase should be a boolean type - combine the availability and stock checks', ) }) @@ -76,11 +76,11 @@ await test('isNotAvailable should be false (!isAvailable)', () => { assert.strictEqual( solution.isNotAvailable, false, - '🚨 isNotAvailable should be false (the opposite of isAvailable which is true) - use the ! operator: !isAvailable', + '🚨 isNotAvailable should be false (the opposite of isAvailable, which is true)', ) assert.strictEqual( typeof solution.isNotAvailable, 'boolean', - '🚨 isNotAvailable should be a boolean type - use the ! operator to invert isAvailable', + '🚨 isNotAvailable should be a boolean type - invert isAvailable', ) }) diff --git a/exercises/03.primitive-types/04.problem.null-and-undefined/README.mdx b/exercises/03.primitive-types/04.problem.null-and-undefined/README.mdx index 330188b..f03994c 100644 --- a/exercises/03.primitive-types/04.problem.null-and-undefined/README.mdx +++ b/exercises/03.primitive-types/04.problem.null-and-undefined/README.mdx @@ -18,9 +18,20 @@ const deletedAt = null // intentionally empty 🐨 Open and: -1. Create a variable `discountCode` set to `undefined` -2. Create a variable `lastPurchaseDate` set to `null` -3. Log both variables to see their values +1. Create `discountCode` set explicitly to `undefined` +2. Create `lastPurchaseDate` set explicitly to `null` +3. Optionally log both variables so you can see their values in the console +4. Export both variables + +## Required exports + +- `discountCode` +- `lastPurchaseDate` + +## Completion criteria + +- `discountCode` is `undefined` +- `lastPurchaseDate` is `null` πŸ“œ [TypeScript Handbook - Null and Undefined](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#null-and-undefined) diff --git a/exercises/03.primitive-types/04.problem.null-and-undefined/index.ts b/exercises/03.primitive-types/04.problem.null-and-undefined/index.ts index c158cb0..cced6f4 100644 --- a/exercises/03.primitive-types/04.problem.null-and-undefined/index.ts +++ b/exercises/03.primitive-types/04.problem.null-and-undefined/index.ts @@ -9,5 +9,5 @@ // console.log('discountCode:', discountCode) // console.log('lastPurchaseDate:', lastPurchaseDate) -// 🐨 Export your variables so we can verify your work +// 🐨 Export discountCode and lastPurchaseDate // export { discountCode, lastPurchaseDate } diff --git a/exercises/03.primitive-types/05.problem.bigint-and-symbol/README.mdx b/exercises/03.primitive-types/05.problem.bigint-and-symbol/README.mdx index cec4838..8b8d6e9 100644 --- a/exercises/03.primitive-types/05.problem.bigint-and-symbol/README.mdx +++ b/exercises/03.primitive-types/05.problem.bigint-and-symbol/README.mdx @@ -40,9 +40,26 @@ Symbols are often used for "hidden" object properties or library-internal keys. 🐨 Open and: -1. Create a bigint literal with the `n` suffix -2. Perform arithmetic with bigint values -3. Create symbols and observe their uniqueness +1. Create `largeNumber` as the bigint `9007199254740993n` +2. Create `anotherLarge` as the bigint `1000000000000000000n` +3. Create `sum` by adding those two bigints +4. Create `userId` with `Symbol('user-id')` +5. Create `anotherId` with the same description `Symbol('user-id')` +6. Create `areEqual` by comparing `userId === anotherId`, then inspect the + result +7. Export all six names + +## Required exports + +`largeNumber`, `anotherLarge`, `sum`, `userId`, `anotherId`, `areEqual` + +## Completion criteria + +- `largeNumber` is `9007199254740993n` (`typeof` `"bigint"`) +- `anotherLarge` is `1000000000000000000n` +- `sum` equals the sum of those two bigints +- `userId` and `anotherId` are both symbols +- `areEqual` reflects whether those two symbols compare equal with `===` πŸ’° BigInt literals use the `n` suffix. diff --git a/exercises/03.primitive-types/05.problem.bigint-and-symbol/index.ts b/exercises/03.primitive-types/05.problem.bigint-and-symbol/index.ts index 48ddf4c..b912e0d 100644 --- a/exercises/03.primitive-types/05.problem.bigint-and-symbol/index.ts +++ b/exercises/03.primitive-types/05.problem.bigint-and-symbol/index.ts @@ -12,15 +12,14 @@ // 🐨 Create another symbol called `anotherId` with the same description 'user-id' -// 🐨 Create a variable `areEqual` that compares userId === anotherId -// This will be false because each Symbol() call creates a unique value! +// 🐨 Create `areEqual` that compares userId === anotherId // Test - uncomment when ready // console.log('Large number:', largeNumber) // console.log('Sum of bigints:', sum) // console.log('userId:', userId) // console.log('anotherId:', anotherId) -// console.log('Are symbols equal?', areEqual) // false +// console.log('Are symbols equal?', areEqual) -// 🐨 Export your variables so we can verify your work +// 🐨 Export largeNumber, anotherLarge, sum, userId, anotherId, and areEqual // export { largeNumber, anotherLarge, sum, userId, anotherId, areEqual } diff --git a/exercises/03.primitive-types/05.solution.bigint-and-symbol/index.test.ts b/exercises/03.primitive-types/05.solution.bigint-and-symbol/index.test.ts index c4af6a0..463d976 100644 --- a/exercises/03.primitive-types/05.solution.bigint-and-symbol/index.test.ts +++ b/exercises/03.primitive-types/05.solution.bigint-and-symbol/index.test.ts @@ -13,7 +13,7 @@ await test('largeNumber should be a bigint with correct value', () => { assert.strictEqual( typeof solution.largeNumber, 'bigint', - '🚨 largeNumber should be type bigint - use the n suffix: 9007199254740993n', + '🚨 largeNumber should be type bigint (use a bigint literal)', ) assert.strictEqual( solution.largeNumber, @@ -73,7 +73,7 @@ await test('userId should be a symbol', () => { assert.strictEqual( typeof solution.userId, 'symbol', - '🚨 userId should be type symbol - use Symbol("user-id")', + '🚨 userId should be type symbol with description "user-id"', ) }) diff --git a/exercises/03.primitive-types/06.problem.truthy-falsy/README.mdx b/exercises/03.primitive-types/06.problem.truthy-falsy/README.mdx index 2e2e58f..c4dfdcd 100644 --- a/exercises/03.primitive-types/06.problem.truthy-falsy/README.mdx +++ b/exercises/03.primitive-types/06.problem.truthy-falsy/README.mdx @@ -17,16 +17,40 @@ Falsy values: You can convert any value to a boolean with `Boolean(value)` or `!!value`. -🐨 Open and: - -1. Create `hasUsername` based on the truthiness of `username` -2. Create `hasNickname` based on the truthiness of `nickname` -3. Create `hasAge` based on the truthiness of `age` -4. Create `hasNotes` based on the truthiness of `notes` -5. Create `canCheckout` that's `true` when `cartTotal` is truthy **and** - `hasAcceptedTerms` is true -6. Create `canCreateAccount` that's `true` when `hasUsername`, `email`, and - `password` are all truthy +🐨 Open . The starter provides these fixtures: + +| Name | Value | +| ------------------ | -------------------- | +| `username` | `'kent'` | +| `nickname` | `''` (empty string) | +| `age` | `0` | +| `email` | `'kent@epicweb.dev'` | +| `password` | `''` (empty string) | +| `notes` | `undefined` | +| `cartTotal` | `42` | +| `hasAcceptedTerms` | `false` | + +Create and export: + +1. `hasUsername` β€” boolean for whether `username` is truthy +2. `hasNickname` β€” boolean for whether `nickname` is truthy +3. `hasAge` β€” boolean for whether `age` is truthy +4. `hasNotes` β€” boolean for whether `notes` is truthy +5. `canCheckout` β€” `true` only when `cartTotal` is truthy **and** + `hasAcceptedTerms` is `true` +6. `canCreateAccount` β€” `true` only when `hasUsername`, `email`, and `password` + are all truthy + +## Required exports + +`hasUsername`, `hasNickname`, `hasAge`, `hasNotes`, `canCheckout`, +`canCreateAccount` + +## Completion criteria + +Each export must be a real boolean (`typeof` `"boolean"`). Use the fixtures and +the falsy list above to reason about (or log) what each expression evaluates +toβ€”don't hardcode the answers. πŸ’° Convert values to booleans when you need a strict true/false. diff --git a/exercises/03.primitive-types/06.problem.truthy-falsy/index.ts b/exercises/03.primitive-types/06.problem.truthy-falsy/index.ts index 934167b..4c7f568 100644 --- a/exercises/03.primitive-types/06.problem.truthy-falsy/index.ts +++ b/exercises/03.primitive-types/06.problem.truthy-falsy/index.ts @@ -10,18 +10,18 @@ const notes = undefined const cartTotal = 42 const hasAcceptedTerms = false -// 🐨 Create a variable `hasUsername` based on the truthiness of `username` +// 🐨 Create `hasUsername` as a boolean based on the truthiness of `username` -// 🐨 Create a variable `hasNickname` based on the truthiness of `nickname` +// 🐨 Create `hasNickname` as a boolean based on the truthiness of `nickname` -// 🐨 Create a variable `hasAge` based on the truthiness of `age` +// 🐨 Create `hasAge` as a boolean based on the truthiness of `age` -// 🐨 Create a variable `hasNotes` based on the truthiness of `notes` +// 🐨 Create `hasNotes` as a boolean based on the truthiness of `notes` -// 🐨 Create a variable `canCheckout` that is true when cartTotal is truthy AND +// 🐨 Create `canCheckout` that is true when cartTotal is truthy AND // hasAcceptedTerms is true -// 🐨 Create a variable `canCreateAccount` that is true when hasUsername, email, +// 🐨 Create `canCreateAccount` that is true when hasUsername, email, // and password are all truthy // βœ… Verification @@ -38,5 +38,5 @@ console.log('Can checkout:', canCheckout) // @ts-expect-error - πŸ’£ remove this comment console.log('Can create account:', canCreateAccount) -// 🐨 Export your variables so we can verify your work +// 🐨 Export hasUsername, hasNickname, hasAge, hasNotes, canCheckout, canCreateAccount // export { hasUsername, hasNickname, hasAge, hasNotes, canCheckout, canCreateAccount } diff --git a/exercises/03.primitive-types/06.solution.truthy-falsy/index.test.ts b/exercises/03.primitive-types/06.solution.truthy-falsy/index.test.ts index 7bd27ce..7d89002 100644 --- a/exercises/03.primitive-types/06.solution.truthy-falsy/index.test.ts +++ b/exercises/03.primitive-types/06.solution.truthy-falsy/index.test.ts @@ -13,7 +13,7 @@ await test('hasUsername should be true', () => { assert.strictEqual( typeof solution.hasUsername, 'boolean', - '🚨 hasUsername should be a boolean - use Boolean(username) or !!username', + '🚨 hasUsername should be a boolean based on the truthiness of username', ) assert.strictEqual( solution.hasUsername, @@ -33,7 +33,7 @@ await test('hasNickname should be false', () => { assert.strictEqual( typeof solution.hasNickname, 'boolean', - '🚨 hasNickname should be a boolean - use Boolean(nickname) or !!nickname', + '🚨 hasNickname should be a boolean based on the truthiness of nickname', ) assert.strictEqual( solution.hasNickname, @@ -53,7 +53,7 @@ await test('hasAge should be false', () => { assert.strictEqual( typeof solution.hasAge, 'boolean', - '🚨 hasAge should be a boolean - use Boolean(age) or !!age', + '🚨 hasAge should be a boolean based on the truthiness of age', ) assert.strictEqual( solution.hasAge, @@ -73,7 +73,7 @@ await test('hasNotes should be false', () => { assert.strictEqual( typeof solution.hasNotes, 'boolean', - '🚨 hasNotes should be a boolean - use Boolean(notes) or !!notes', + '🚨 hasNotes should be a boolean based on the truthiness of notes', ) assert.strictEqual( solution.hasNotes, diff --git a/exercises/04.control-flow/01.problem.conditionals/README.mdx b/exercises/04.control-flow/01.problem.conditionals/README.mdx index 4763d42..b097ee5 100644 --- a/exercises/04.control-flow/01.problem.conditionals/README.mdx +++ b/exercises/04.control-flow/01.problem.conditionals/README.mdx @@ -5,16 +5,27 @@ πŸ‘¨β€πŸ’Ό We're building a grade calculator for a school system. Based on a numeric score, we need to determine the letter grade. -🐨 Open and: +🐨 Open . The starter sets `score` to `85`. -1. Write an `if`/`else if`/`else` chain to determine the letter grade: - - 90 and above: "A" - - 80-89: "B" - - 70-79: "C" - - 60-69: "D" - - Below 60: "F" +1. Create a `grade` string using an `if`/`else if`/`else` chain: + - 90 and above: `"A"` + - 80–89: `"B"` + - 70–79: `"C"` + - 60–69: `"D"` + - Below 60: `"F"` +2. Create `passed` as a boolean that is `true` when the letter grade is C or + above (that means grades `"A"`, `"B"`, or `"C"`) +3. Export `score`, `grade`, and `passed` -2. Add a check to see if the student passed (grade C or above) +## Required exports + +`score`, `grade`, `passed` + +## Completion criteria (with `score = 85`) + +- `score` remains `85` +- `grade` is `"B"` +- `passed` is `true` πŸ’° Check the highest ranges first so the first match wins. diff --git a/exercises/04.control-flow/01.problem.conditionals/index.ts b/exercises/04.control-flow/01.problem.conditionals/index.ts index 98ce63e..59ebfcd 100644 --- a/exercises/04.control-flow/01.problem.conditionals/index.ts +++ b/exercises/04.control-flow/01.problem.conditionals/index.ts @@ -12,11 +12,11 @@ const score: number = 85 // - 60-69: "D" // - Below 60: "F" -// 🐨 Create a variable `passed` that is true if grade is C or above +// 🐨 Create `passed` that is true if grade is C or above (A, B, or C) // console.log(`Score: ${score}`) // console.log(`Grade: ${grade}`) // console.log(`Passed: ${passed}`) -// 🐨 Export your variables so we can verify your work +// 🐨 Export score, grade, and passed // export { score, grade, passed } diff --git a/exercises/04.control-flow/02.problem.switch-statements/README.mdx b/exercises/04.control-flow/02.problem.switch-statements/README.mdx index 2b80631..4a98dea 100644 --- a/exercises/04.control-flow/02.problem.switch-statements/README.mdx +++ b/exercises/04.control-flow/02.problem.switch-statements/README.mdx @@ -5,17 +5,26 @@ πŸ‘¨β€πŸ’Ό We've been using `if`/`else if` chains, but when you're checking one value against many possible matches, a `switch` statement is often cleaner. -🐨 Open and: - -1. Create a `description` variable to hold the feedback text -2. Write a `switch` statement that checks the `grade` value and sets the - appropriate description: - - 'A' β†’ "Excellent" - - 'B' β†’ "Good" - - 'C' β†’ "Satisfactory" - - 'D' β†’ "Needs Improvement" - - 'F' β†’ "Failing" - - Any other value β†’ "Invalid grade" +🐨 Open . The starter sets `grade` to `'B'`. + +1. Create a `description` string +2. Write a `switch` on `grade` that sets `description` to these exact values: + - `'A'` β†’ `"Excellent"` + - `'B'` β†’ `"Good"` + - `'C'` β†’ `"Satisfactory"` + - `'D'` β†’ `"Needs Improvement"` + - `'F'` β†’ `"Failing"` + - any other value β†’ `"Invalid grade"` +3. Export `grade` and `description` + +## Required exports + +`grade`, `description` + +## Completion criteria (with `grade = 'B'`) + +- `grade` remains `"B"` +- `description` is `"Good"` πŸ’° Use `switch` with `case` branches and a `default` for all other values. diff --git a/exercises/04.control-flow/02.problem.switch-statements/index.ts b/exercises/04.control-flow/02.problem.switch-statements/index.ts index 26820c9..f880737 100644 --- a/exercises/04.control-flow/02.problem.switch-statements/index.ts +++ b/exercises/04.control-flow/02.problem.switch-statements/index.ts @@ -5,16 +5,16 @@ const grade: string = 'B' // 🐨 Create a variable `description` of type string -// 🐨 Write a switch statement on `grade`: -// - case 'A': set description to "Excellent" -// - case 'B': set description to "Good" -// - case 'C': set description to "Satisfactory" -// - case 'D': set description to "Needs Improvement" -// - case 'F': set description to "Failing" -// - default: set description to "Invalid grade" -// πŸ’° Each case should avoid falling through (use `break` in each case) by adding a `break` statement +// 🐨 Write a switch statement on `grade` with these exact strings: +// - case 'A': "Excellent" +// - case 'B': "Good" +// - case 'C': "Satisfactory" +// - case 'D': "Needs Improvement" +// - case 'F': "Failing" +// - default: "Invalid grade" +// πŸ’° End each case so it does not fall through to the next one // console.log(`Grade ${grade}: ${description}`) -// 🐨 Export your variables so we can verify your work +// 🐨 Export grade and description // export { grade, description } diff --git a/exercises/04.control-flow/03.problem.loops/README.mdx b/exercises/04.control-flow/03.problem.loops/README.mdx index ea45876..e2e0662 100644 --- a/exercises/04.control-flow/03.problem.loops/README.mdx +++ b/exercises/04.control-flow/03.problem.loops/README.mdx @@ -4,8 +4,24 @@ πŸ‘¨β€πŸ’Ό Let's practice a simple `for` loop by building a numbered list. -🐨 Open and use a `for` loop to build a string -with labels for exhibits 1 through 5. Each label should be on its own line. +🐨 Open and: + +1. Create `exhibitLabels` starting as an empty string +2. Use a `for` loop to append labels for exhibits `1` through `5` +3. Each label must be exactly `Exhibit N` followed by a newline (`\n`), including + a trailing newline after exhibit 5 + +## Required exports + +- `exhibitLabels` + +## Completion criteria + +`exhibitLabels` must equal exactly (note the final `\n`): + +```ts +'Exhibit 1\nExhibit 2\nExhibit 3\nExhibit 4\nExhibit 5\n' +``` ## How a `for` loop works diff --git a/exercises/04.control-flow/03.problem.loops/index.ts b/exercises/04.control-flow/03.problem.loops/index.ts index c0f420a..94d0f77 100644 --- a/exercises/04.control-flow/03.problem.loops/index.ts +++ b/exercises/04.control-flow/03.problem.loops/index.ts @@ -4,10 +4,10 @@ // 🐨 Create a variable `exhibitLabels` starting as an empty string // 🐨 Write a for loop that counts from 1 to 5 -// 🐨 On each pass, add a line like "Exhibit 1" to the string -// 🐨 Put each label on its own line using "\n" +// 🐨 On each pass, append "Exhibit N" plus a newline ("\n") +// πŸ’° The finished string should end with a newline after Exhibit 5 // console.log(exhibitLabels) -// 🐨 Export your variable so we can verify your work +// 🐨 Export exhibitLabels so we can verify your work // export { exhibitLabels } diff --git a/exercises/04.control-flow/04.problem.nested-loops/README.mdx b/exercises/04.control-flow/04.problem.nested-loops/README.mdx index d36bf18..b873d15 100644 --- a/exercises/04.control-flow/04.problem.nested-loops/README.mdx +++ b/exercises/04.control-flow/04.problem.nested-loops/README.mdx @@ -5,7 +5,13 @@ πŸ‘¨β€πŸ’Ό Let's generate a seating chart for a small theater. Each row has multiple seats, so we'll need a loop inside a loop. -🐨 Open and build a string that looks like this: +🐨 Open . The starter provides: + +- `rows = ['A', 'B', 'C']` +- `seatsPerRow = 4` + +Build and export `seatChart` as a string that looks exactly like this +(spaces between seats, newline after **every** row including the last): ``` A1 A2 A3 A4 @@ -13,11 +19,23 @@ B1 B2 B3 B4 C1 C2 C3 C4 ``` -Each row should be on its own line using `\n`. +As a single string value, that is: + +```ts +'A1 A2 A3 A4\nB1 B2 B3 B4\nC1 C2 C3 C4\n' +``` Use **nested `for` loops**: -- The **outer loop** controls which row you're on -- The **inner loop** builds the seat labels for that row +- The **outer loop** walks the `rows` array +- The **inner loop** builds seat numbers `1` through `seatsPerRow` + +## Required exports + +- `seatChart` + +## Completion criteria + +`seatChart` must equal the exact string above (including the trailing `\n`). πŸ“œ [MDN - for statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) diff --git a/exercises/04.control-flow/04.problem.nested-loops/index.ts b/exercises/04.control-flow/04.problem.nested-loops/index.ts index b3fe31c..aed79db 100644 --- a/exercises/04.control-flow/04.problem.nested-loops/index.ts +++ b/exercises/04.control-flow/04.problem.nested-loops/index.ts @@ -6,11 +6,11 @@ const seatsPerRow = 4 // 🐨 Create a variable `seatChart` starting as an empty string -// 🐨 Use nested for loops to build the seating chart -// 🐨 Each row should include seat labels like "A1 A2 A3 A4" -// 🐨 Put each row on its own line using "\n" +// 🐨 Use nested for loops to build the seating chart from `rows` and `seatsPerRow` +// 🐨 Each row should look like "A1 A2 A3 A4" (spaces between seats) +// 🐨 End every rowβ€”including the lastβ€”with "\n" // console.log(seatChart) -// 🐨 Export your variable so we can verify your work +// 🐨 Export seatChart so we can verify your work // export { seatChart } diff --git a/exercises/04.control-flow/05.problem.ternary-operator/README.mdx b/exercises/04.control-flow/05.problem.ternary-operator/README.mdx index f7a0a7a..aa7618f 100644 --- a/exercises/04.control-flow/05.problem.ternary-operator/README.mdx +++ b/exercises/04.control-flow/05.problem.ternary-operator/README.mdx @@ -33,12 +33,29 @@ if (age >= 18) { const status = age >= 18 ? 'adult' : 'minor' ``` -🐨 Open and use the ternary operator to: +🐨 Open . The starter provides: -1. Create `weatherDescription` - "hot" if temperature > 30, otherwise - "comfortable" -2. Create `passed` - true if score >= 70, otherwise false -3. Create `stockMessage` - "In stock" if stock > 0, otherwise "Out of stock" +- `temperature = 25` +- `score = 85` +- `stock = 0` + +Use the ternary operator to create: + +1. `weatherDescription` β€” `"hot"` if `temperature > 30`, otherwise + `"comfortable"` +2. `passed` β€” `true` if `score >= 70`, otherwise `false` +3. `stockMessage` β€” `"In stock"` if `stock > 0`, otherwise `"Out of stock"` + +Export all three. + +## Required exports + +`weatherDescription`, `passed`, `stockMessage` + +## Completion criteria + +Each export follows the ternary rules above for the given fixtures. Log or +inspect the values to confirmβ€”don't hardcode answers that ignore the conditions. The ternary operator is an **expression** that produces a value, while diff --git a/exercises/04.control-flow/05.problem.ternary-operator/index.ts b/exercises/04.control-flow/05.problem.ternary-operator/index.ts index b3e144b..def7f9a 100644 --- a/exercises/04.control-flow/05.problem.ternary-operator/index.ts +++ b/exercises/04.control-flow/05.problem.ternary-operator/index.ts @@ -3,22 +3,22 @@ const temperature = 25 -// 🐨 Create a variable `weatherDescription` using a ternary operator -// It should be "hot" if temperature > 30, otherwise "comfortable" +// 🐨 Create `weatherDescription` using a ternary operator +// "hot" if temperature > 30, otherwise "comfortable" const score = 85 -// 🐨 Create a variable `passed` using a ternary operator -// It should be true if score >= 70, otherwise false +// 🐨 Create `passed` using a ternary operator +// true if score >= 70, otherwise false const stock = 0 -// 🐨 Create a variable `stockMessage` using a ternary operator -// It should be "In stock" if stock > 0, otherwise "Out of stock" +// 🐨 Create `stockMessage` using a ternary operator +// "In stock" if stock > 0, otherwise "Out of stock" // console.log(`Temperature: ${temperature} β†’ ${weatherDescription}`) // console.log(`Score: ${score} β†’ ${passed ? 'Passed' : 'Failed'}`) // console.log(`Stock: ${stock} β†’ ${stockMessage}`) -// 🐨 Export your variables so we can verify your work +// 🐨 Export weatherDescription, passed, and stockMessage // export { weatherDescription, passed, stockMessage } diff --git a/exercises/04.control-flow/06.problem.errors/README.mdx b/exercises/04.control-flow/06.problem.errors/README.mdx index f476574..85afb2e 100644 --- a/exercises/04.control-flow/06.problem.errors/README.mdx +++ b/exercises/04.control-flow/06.problem.errors/README.mdx @@ -18,15 +18,38 @@ try { } ``` -🐨 Open and: +🐨 Open . The starter provides: -1. Throw an error when the input isn't a valid number -2. Wrap the conversion in a `try`/`catch` -3. Set `resultMessage` to show either the parsed value or the error message +- `rawInput = 'not-a-number'` +- `resultMessage` starting as `''` +- `hadError` starting as `false` + +Parse `rawInput` as a number inside a `try`/`catch`. If the input is not a valid +number, throw an error whose message is exactly +`Invalid number: not-a-number` (the prefix `Invalid number: ` plus the raw +input). On success, set `resultMessage` to describe the parsed value using the +format `Parsed value: `. On failure, set `hadError` to `true` and set +`resultMessage` to `Error: ` (so the thrown message appears after +the `Error: ` prefix). + +Export `resultMessage` and `hadError`. + +## Required exports + +`resultMessage`, `hadError` + +## Completion criteria (with this fixture) + +- `hadError` is `true` +- `resultMessage` is exactly `Error: Invalid number: not-a-number` + +Edge cases to keep in mind: valid numeric strings should succeed and set +`resultMessage` to the success format (no error); invalid input must throw and +be caught without crashing the program. - In a `catch` block, the `error` value is `unknown`. Use - `error instanceof Error` before reading `error.message`. + In a `catch` block, the caught value is typed as `unknown`. Narrow it before + you read properties like a message string. πŸ“œ [MDN - throw](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw) diff --git a/exercises/04.control-flow/06.problem.errors/index.ts b/exercises/04.control-flow/06.problem.errors/index.ts index fb3541c..6bff107 100644 --- a/exercises/04.control-flow/06.problem.errors/index.ts +++ b/exercises/04.control-flow/06.problem.errors/index.ts @@ -6,11 +6,11 @@ const rawInput = 'not-a-number' let resultMessage = '' let hadError = false -// 🐨 Use a try/catch block to convert rawInput to a number -// - Inside try, create parsedValue with Number(rawInput) -// - If Number.isNaN(parsedValue), throw a new Error with message `Invalid number: ${rawInput}` -// - If it succeeds, set resultMessage to `Parsed value: ${parsedValue}` -// - If it throws, set hadError to true and resultMessage to `Error: ${message}` +// 🐨 Parse rawInput as a number inside try/catch +// - Invalid input: throw an error with message "Invalid number: " + the raw input +// - Success: resultMessage = "Parsed value: " + the parsed number +// - Catch: hadError = true, resultMessage = "Error: " + the error message +// πŸ’° The caught value is unknown β€” narrow it before reading a message // console.log(resultMessage) diff --git a/exercises/05.functions/01.problem.function-declaration/README.mdx b/exercises/05.functions/01.problem.function-declaration/README.mdx index af33e0b..ea1c257 100644 --- a/exercises/05.functions/01.problem.function-declaration/README.mdx +++ b/exercises/05.functions/01.problem.function-declaration/README.mdx @@ -13,8 +13,20 @@ function getFavoriteNumber(): number { } ``` -🐨 Open and create `getMessage` that returns the -string `"Hello, functions!"`, with an explicit return type. +🐨 Open and: + +1. Create a function declaration named `getMessage` +2. Give it an explicit return type of `string` +3. Return exactly `"Hello, functions!"` +4. Export `getMessage` + +## Required exports + +- `getMessage` + +## Completion criteria + +- `getMessage()` returns `"Hello, functions!"` πŸ’° Remember to return a string and annotate the return type. diff --git a/exercises/05.functions/01.problem.function-declaration/index.ts b/exercises/05.functions/01.problem.function-declaration/index.ts index 48d1318..788e820 100644 --- a/exercises/05.functions/01.problem.function-declaration/index.ts +++ b/exercises/05.functions/01.problem.function-declaration/index.ts @@ -1,11 +1,12 @@ // Function Declarations // A named function that returns a value -// 🐨 Create a function named `getMessage` that returns "Hello, functions!" -// Make sure to add an explicit return type of string. +// 🐨 Create a function declaration named `getMessage` +// - Explicit return type: string +// - Returns exactly "Hello, functions!" // βœ… Test your function // console.log(getMessage()) // "Hello, functions!" -// 🐨 Export your function so we can verify your work +// 🐨 Export getMessage // export { getMessage } diff --git a/exercises/05.functions/02.problem.parameters/README.mdx b/exercises/05.functions/02.problem.parameters/README.mdx index 9a5e448..694e729 100644 --- a/exercises/05.functions/02.problem.parameters/README.mdx +++ b/exercises/05.functions/02.problem.parameters/README.mdx @@ -5,15 +5,30 @@ πŸ‘¨β€πŸ’Ό We need utility functions for our e-commerce platform. Let's focus on functions that accept clear inputs and return the right type. -🐨 Open and create these functions: +🐨 Open and create these exported functions with +typed parameters and explicit return types: -1. `calculateTax(amount: number, rate: number)` - Returns the tax amount -2. `formatPrice(cents: number)` - Converts cents to dollar string (e.g., 1999 β†’ - "$19.99") -3. `applyDiscount(price: number, discountPercent: number)` - Returns discounted - price +1. `calculateTax(amount: number, rate: number): number` β€” returns the tax amount + for the given amount and rate. Examples: `calculateTax(100, 0.08)` β†’ `8`; + `calculateTax(50, 0.1)` β†’ `5` -Return values are already familiar from 5.1β€”focus on **parameter types** here, -but keep the return types explicit too. +2. `formatPrice(cents: number): string` β€” converts whole cents into a dollar + string with a `$` prefix and exactly two decimal places. Examples: + `formatPrice(1999)` β†’ `"$19.99"`; `formatPrice(100)` β†’ `"$1.00"`; + `formatPrice(50)` β†’ `"$0.50"` + +3. `applyDiscount(price: number, discountPercent: number): number` β€” returns the + price after a percentage discount is applied. Examples: + `applyDiscount(100, 20)` β†’ `80`; `applyDiscount(50, 10)` β†’ `45`; + `applyDiscount(200, 25)` β†’ `150` + +## Required exports + +`calculateTax`, `formatPrice`, `applyDiscount` + +## Completion criteria + +The examples above must all pass. Prefer keeping return types explicit even +though this step focuses on parameter types. πŸ“œ [TypeScript Handbook - More on Functions](https://www.typescriptlang.org/docs/handbook/2/functions.html) diff --git a/exercises/05.functions/02.problem.parameters/index.ts b/exercises/05.functions/02.problem.parameters/index.ts index 893f496..fd15073 100644 --- a/exercises/05.functions/02.problem.parameters/index.ts +++ b/exercises/05.functions/02.problem.parameters/index.ts @@ -1,22 +1,20 @@ // E-commerce Utility Functions // Creating functions with typed parameters and return values -// 🐨 Create a function `calculateTax` that: -// - Takes `amount` (number) and `rate` (number) -// - Returns the tax amount (amount * rate) +// 🐨 Create `calculateTax(amount: number, rate: number): number` +// πŸ’° Examples: (100, 0.08) β†’ 8; (50, 0.1) β†’ 5 -// 🐨 Create a function `formatPrice` that: -// - Takes `cents` (number) -// - Returns a formatted dollar string like "$19.99" +// 🐨 Create `formatPrice(cents: number): string` +// πŸ’° "$" prefix and exactly two decimal places +// Examples: 1999 β†’ "$19.99", 100 β†’ "$1.00", 50 β†’ "$0.50" -// 🐨 Create a function `applyDiscount` that: -// - Takes `price` (number) and `discountPercent` (number) -// - Returns the discounted price +// 🐨 Create `applyDiscount(price: number, discountPercent: number): number` +// πŸ’° Examples: (100, 20) β†’ 80; (50, 10) β†’ 45; (200, 25) β†’ 150 // βœ… Test your functions // console.log(calculateTax(100, 0.08)) // 8 // console.log(formatPrice(1999)) // "$19.99" // console.log(applyDiscount(100, 20)) // 80 -// 🐨 Export your functions so we can verify your work +// 🐨 Export calculateTax, formatPrice, and applyDiscount // export { calculateTax, formatPrice, applyDiscount } diff --git a/exercises/05.functions/02.solution.parameters/index.test.ts b/exercises/05.functions/02.solution.parameters/index.test.ts index 86ac58b..2b70ff8 100644 --- a/exercises/05.functions/02.solution.parameters/index.test.ts +++ b/exercises/05.functions/02.solution.parameters/index.test.ts @@ -13,12 +13,12 @@ await test('calculateTax should calculate tax correctly', () => { assert.strictEqual( solution.calculateTax(100, 0.08), 8, - '🚨 calculateTax(100, 0.08) should return 8 - multiply the amount by the tax rate', + '🚨 calculateTax(100, 0.08) should return 8', ) assert.strictEqual( solution.calculateTax(50, 0.1), 5, - '🚨 calculateTax(50, 0.1) should return 5 - multiply the amount by the tax rate', + '🚨 calculateTax(50, 0.1) should return 5', ) }) @@ -33,17 +33,17 @@ await test('formatPrice should format cents as dollars', () => { assert.strictEqual( solution.formatPrice(1999), '$19.99', - '🚨 formatPrice(1999) should return "$19.99" - divide by 100 and format with dollar sign and 2 decimals', + '🚨 formatPrice(1999) should return "$19.99"', ) assert.strictEqual( solution.formatPrice(100), '$1.00', - '🚨 formatPrice(100) should return "$1.00" - divide by 100 and format with dollar sign and 2 decimals', + '🚨 formatPrice(100) should return "$1.00"', ) assert.strictEqual( solution.formatPrice(50), '$0.50', - '🚨 formatPrice(50) should return "$0.50" - divide by 100 and format with dollar sign and 2 decimals', + '🚨 formatPrice(50) should return "$0.50"', ) }) @@ -58,16 +58,16 @@ await test('applyDiscount should apply discount percentage', () => { assert.strictEqual( solution.applyDiscount(100, 20), 80, - '🚨 applyDiscount(100, 20) should return 80 - subtract the discount percentage from the price', + '🚨 applyDiscount(100, 20) should return 80', ) assert.strictEqual( solution.applyDiscount(50, 10), 45, - '🚨 applyDiscount(50, 10) should return 45 - subtract the discount percentage from the price', + '🚨 applyDiscount(50, 10) should return 45', ) assert.strictEqual( solution.applyDiscount(200, 25), 150, - '🚨 applyDiscount(200, 25) should return 150 - subtract the discount percentage from the price', + '🚨 applyDiscount(200, 25) should return 150', ) }) diff --git a/exercises/05.functions/03.problem.type-inference/README.mdx b/exercises/05.functions/03.problem.type-inference/README.mdx index 0235dd5..65bf376 100644 --- a/exercises/05.functions/03.problem.type-inference/README.mdx +++ b/exercises/05.functions/03.problem.type-inference/README.mdx @@ -28,14 +28,31 @@ function add(a: number, b: number) { 🐨 Open and: -1. Observe what TypeScript infers for each function -2. Hover over function names to see the inferred return types -3. Add an explicit return type where it catches a bug +1. Hover over `multiply` and notice TypeScript infers its return type as + `number` without an annotation +2. On `divide`, add an explicit return type of `: number` so TypeScript flags the + buggy string return +3. Fix `divide` so dividing by zero throws an `Error` with the exact message + `"Cannot divide by zero"` (instead of returning a string) +4. Create `isEven(n: number)` that returns whether `n` is even; let TypeScript + infer the boolean return type +5. Export `multiply`, `divide`, and `isEven` + +## Required exports + +`multiply`, `divide`, `isEven` + +## Completion criteria + +- `multiply(4, 5)` β†’ `20` (and other products work) +- `divide(10, 2)` β†’ `5`; `divide(7, 2)` β†’ `3.5` +- `divide(10, 0)` throws with message `"Cannot divide by zero"` +- `isEven(4)` / `isEven(0)` β†’ `true`; `isEven(7)` β†’ `false` - This exercise uses: - `throw new Error(message)` - stops execution and raises - an error - `%` (modulo operator) - returns the remainder after division (e.g., - `7 % 2` returns `1`) + `throw new Error(message)` stops normal execution and raises an error. For + `isEven`, choose an arithmetic check that works for positive, negative, and + zero values. πŸ’° In VS Code/Cursor, hover over a function name to see its full type signature. diff --git a/exercises/05.functions/03.problem.type-inference/index.ts b/exercises/05.functions/03.problem.type-inference/index.ts index 2d39d7c..165676b 100644 --- a/exercises/05.functions/03.problem.type-inference/index.ts +++ b/exercises/05.functions/03.problem.type-inference/index.ts @@ -17,10 +17,12 @@ function divide(a: number, b: number) { return a / b } -// 🐨 Fix the bug by throwing an error instead of returning a string: +// 🐨 Fix the bug by throwing an Error with message "Cannot divide by zero" +// instead of returning a string -// 🐨 Create a function `isEven` that returns true if a number is even -// Let TypeScript infer the return type +// 🐨 Create `isEven(n: number)` that returns true for even numbers +// πŸ’° Let TypeScript infer the boolean return type +// πŸ’° A number is even when dividing by 2 leaves no remainder // βœ… Test console.log(multiply(4, 5)) // 20 @@ -28,5 +30,5 @@ console.log(divide(10, 2)) // 5 // console.log(isEven(4)) // true // console.log(isEven(7)) // false -// 🐨 Export your functions so we can verify your work +// 🐨 Export multiply, divide, and isEven // export { multiply, divide, isEven } diff --git a/exercises/05.functions/03.solution.type-inference/index.test.ts b/exercises/05.functions/03.solution.type-inference/index.test.ts index bbfe3c1..529aee3 100644 --- a/exercises/05.functions/03.solution.type-inference/index.test.ts +++ b/exercises/05.functions/03.solution.type-inference/index.test.ts @@ -70,17 +70,17 @@ await test('isEven should return true for even numbers', () => { assert.strictEqual( solution.isEven(4), true, - '🚨 isEven(4) should return true - check if the number modulo 2 equals 0', + '🚨 isEven(4) should return true', ) assert.strictEqual( solution.isEven(2), true, - '🚨 isEven(2) should return true - check if the number modulo 2 equals 0', + '🚨 isEven(2) should return true', ) assert.strictEqual( solution.isEven(0), true, - '🚨 isEven(0) should return true - check if the number modulo 2 equals 0', + '🚨 isEven(0) should return true', ) }) @@ -88,16 +88,16 @@ await test('isEven should return false for odd numbers', () => { assert.strictEqual( solution.isEven(7), false, - '🚨 isEven(7) should return false - check if the number modulo 2 does not equal 0', + '🚨 isEven(7) should return false', ) assert.strictEqual( solution.isEven(3), false, - '🚨 isEven(3) should return false - check if the number modulo 2 does not equal 0', + '🚨 isEven(3) should return false', ) assert.strictEqual( solution.isEven(1), false, - '🚨 isEven(1) should return false - check if the number modulo 2 does not equal 0', + '🚨 isEven(1) should return false', ) }) diff --git a/exercises/05.functions/04.problem.arrow-functions/README.mdx b/exercises/05.functions/04.problem.arrow-functions/README.mdx index a601a91..d1b2a00 100644 --- a/exercises/05.functions/04.problem.arrow-functions/README.mdx +++ b/exercises/05.functions/04.problem.arrow-functions/README.mdx @@ -31,9 +31,32 @@ const double = (n: number): number => n * 2 🐨 Open and: -1. Convert the function declarations to arrow functions -2. Use implicit returns where the function body is a single expression -3. Create a function that uses a callback with arrow functions (no arrays) +1. Convert `double` and `greet` from function declarations to arrow functions + with **implicit returns** +2. Convert `calculateTotal` to an arrow function but keep a block body and + explicit `return` (it has multiple lines) +3. Create an arrow function `isEven(n: number)` that returns whether `n` is even +4. Create `applyToNumber(value: number, transform: (n: number) => number): number` + that applies `transform` to `value` and returns the result +5. Create arrow functions `triple` (multiply by 3) and `square` (multiply a + number by itself) +6. Export: + `double`, `greet`, `calculateTotal`, `isEven`, `applyToNumber`, `triple`, + `square` + +## Required exports + +`double`, `greet`, `calculateTotal`, `isEven`, `applyToNumber`, `triple`, +`square` + +## Completion criteria + +- `double`, `greet`, `calculateTotal`, and `isEven` are arrow functions +- `double(5)` β†’ `10`; `double(0)` β†’ `0`; `double(-3)` β†’ `-6` +- `greet('Alice')` β†’ `"Hello, Alice!"`; `greet('Bob')` β†’ `"Hello, Bob!"` +- `calculateTotal(60, 0.1)` β†’ `66`; `calculateTotal(100, 0.05)` β†’ `105` +- `isEven(4)` / `isEven(0)` β†’ `true`; `isEven(7)` β†’ `false` +- `applyToNumber(5, triple)` β†’ `15`; `applyToNumber(6, square)` β†’ `36` πŸ’° Implicit returns use a single expression and no braces. diff --git a/exercises/05.functions/04.problem.arrow-functions/index.ts b/exercises/05.functions/04.problem.arrow-functions/index.ts index acfd826..0aca132 100644 --- a/exercises/05.functions/04.problem.arrow-functions/index.ts +++ b/exercises/05.functions/04.problem.arrow-functions/index.ts @@ -18,17 +18,16 @@ function calculateTotal(subtotal: number, taxRate: number): number { } // 🐨 Create an arrow function `isEven` that returns true if a number is even -// πŸ’° Short functions can be written more concisely (use `n % 2 === 0`) +// πŸ’° A number is even when dividing by 2 leaves no remainder -// 🐨 Create a function `applyToNumber` that: -// - Takes a number and a transform function -// - Returns the transformed number -// πŸ’° Functions can accept other functions as parameters +// 🐨 Create `applyToNumber(value, transform)` that: +// - Takes a number and a transform function `(n: number) => number` +// - Returns the result of calling transform with that number // 🐨 Create arrow functions: // - `triple` that multiplies a number by 3 // - `square` that multiplies a number by itself -// Then call applyToNumber with each. +// Then you can call applyToNumber with each. -// 🐨 Export your functions so we can verify your work +// 🐨 Export double, greet, calculateTotal, isEven, applyToNumber, triple, square // export { double, greet, calculateTotal, isEven, applyToNumber, triple, square } diff --git a/exercises/05.functions/04.solution.arrow-functions/index.test.ts b/exercises/05.functions/04.solution.arrow-functions/index.test.ts index 288883d..db7b40d 100644 --- a/exercises/05.functions/04.solution.arrow-functions/index.test.ts +++ b/exercises/05.functions/04.solution.arrow-functions/index.test.ts @@ -12,7 +12,7 @@ await test('double is exported', () => { await test('double should be an arrow function', () => { assert.ok( solution.double.toString().includes('=>'), - '🚨 double should be an arrow function - use const double = (n: number) => ...', + '🚨 double should be an arrow function (its source should include =>)', ) assert.strictEqual(solution.double(5), 10, '🚨 double(5) should return 10') assert.strictEqual(solution.double(0), 0, '🚨 double(0) should return 0') @@ -29,7 +29,7 @@ await test('greet is exported', () => { await test('greet should be an arrow function', () => { assert.ok( solution.greet.toString().includes('=>'), - '🚨 greet should be an arrow function - use const greet = (name: string) => ...', + '🚨 greet should be an arrow function (its source should include =>)', ) assert.strictEqual( solution.greet('Alice'), diff --git a/exercises/05.functions/05.problem.jsdoc/README.mdx b/exercises/05.functions/05.problem.jsdoc/README.mdx index f9ea258..65711c7 100644 --- a/exercises/05.functions/05.problem.jsdoc/README.mdx +++ b/exercises/05.functions/05.problem.jsdoc/README.mdx @@ -44,13 +44,42 @@ documentation! | `@throws` | Documents errors the function throws | | `@see` | Links to related documentation | -🐨 Open and add JSDoc comments to each function. +🐨 Open and: + +1. Add JSDoc above `add` with a description, `@param` for `a` and `b`, and + `@returns` +2. Add JSDoc above `greet` with a description, `@param` for `name`, `@returns`, + and an `@example` +3. Add JSDoc above `calculateCompoundInterest` documenting `principal`, `rate` + (decimal), `years`, `@returns`, and an `@example` +4. Create and export `clamp(value: number, min: number, max: number): number` + that returns: + - `min` when `value` is below `min` + - `max` when `value` is above `max` + - `value` when it is already between `min` and `max` (inclusive) +5. Give `clamp` complete JSDoc (description, `@param`, `@returns`, `@example`) + +## Required exports + +`add`, `greet`, `calculateCompoundInterest`, `clamp` + +## Completion criteria + +Automated tests verify behavior (not the JSDoc text itself): + +- `add(2, 3)` β†’ `5`; `add(-1, 1)` β†’ `0` +- `greet('Alice')` β†’ `"Hello, Alice!"` +- `calculateCompoundInterest(1000, 0.05, 10)` β‰ˆ `1628.89` +- `calculateCompoundInterest(100, 0.1, 1)` β‰ˆ `110` +- `clamp(15, 0, 10)` β†’ `10`; `clamp(-5, 0, 10)` β†’ `0`; `clamp(5, 0, 10)` β†’ `5`; + `clamp(0, 0, 10)` β†’ `0`; `clamp(10, 0, 10)` β†’ `10` + +For the learning goal: hover each function in your editor and confirm the JSDoc +appears in the tooltip. - Some functions in this exercise use built-in Math methods: - `Math.pow(base, - exponent)` - raises base to the power of exponent (e.g., `Math.pow(2, 3)` - returns 8) - `Math.max(a, b)` - returns the larger of two numbers - - `Math.min(a, b)` - returns the smaller of two numbers + Some functions in this exercise use built-in Math helpers for powers and for + choosing the larger/smaller of two numbers when clamping a value into a range. πŸ’° Put a brief description immediately after the opening `/**`. diff --git a/exercises/05.functions/05.problem.jsdoc/index.ts b/exercises/05.functions/05.problem.jsdoc/index.ts index 761aba2..d38d886 100644 --- a/exercises/05.functions/05.problem.jsdoc/index.ts +++ b/exercises/05.functions/05.problem.jsdoc/index.ts @@ -16,7 +16,6 @@ function add(a: number, b: number): number { // - @param tag for the `name` parameter // - @returns tag // - @example tag showing how to use the function -// πŸ’° Include an @example block that shows how to call the function function greet(name: string): string { return `Hello, ${name}!` } @@ -36,11 +35,11 @@ function calculateCompoundInterest( return principal * Math.pow(1 + rate, years) } -// 🐨 Create a function called `clamp` that: -// - Takes a value, min, and max -// - Returns the value constrained between min and max -// - Has a complete JSDoc comment with description, @param, @returns, and @example -// πŸ’° Use Math.min/Math.max to keep the value within range +// 🐨 Create `clamp(value, min, max)` that returns value constrained to [min, max] +// - Below min β†’ return min +// - Above max β†’ return max +// - Otherwise β†’ return value +// - Add complete JSDoc: description, @param, @returns, @example -// 🐨 Export your functions so we can verify your work +// 🐨 Export add, greet, calculateCompoundInterest, and clamp // export { add, greet, calculateCompoundInterest, clamp } diff --git a/exercises/06.void-and-never/01.problem.void-functions/README.mdx b/exercises/06.void-and-never/01.problem.void-functions/README.mdx index 47c7c6c..e4f2992 100644 --- a/exercises/06.void-and-never/01.problem.void-functions/README.mdx +++ b/exercises/06.void-and-never/01.problem.void-functions/README.mdx @@ -12,14 +12,24 @@ Examples of side effects: - Sending data to a server - Playing a sound -🐨 Open and: +🐨 Open and create these exported functions. +Each takes a `message: string` and returns `void` (no useful return value): -1. Create a `logInfo` function that logs a message with "[INFO]" prefix -2. Create a `logError` function that logs with "[ERROR]" prefix -3. Create a `logWithTimestamp` function that includes the current time +1. `logInfo` β€” logs with an `[INFO]` prefix, e.g. `[INFO] Application started` +2. `logError` β€” logs with an `[ERROR]` prefix, e.g. `[ERROR] Connection failed` +3. `logWithTimestamp` β€” logs with an ISO timestamp in brackets, e.g. + `[2024-01-15T12:00:00.000Z] User logged in` (use the current time) -πŸ’° Use `Date` to get the current time and include it in the log. +## Required exports -πŸ’° Void functions don’t return a value. +`logInfo`, `logError`, `logWithTimestamp` + +## Completion criteria + +- Each function is callable and returns `undefined` (the runtime value of + `void`) +- When you call them, console output uses the prefix/timestamp formats above + +πŸ’° Void functions don't return a valueβ€”annotate the return type as `void`. πŸ“œ [TypeScript Handbook - void](https://www.typescriptlang.org/docs/handbook/2/functions.html#void) diff --git a/exercises/06.void-and-never/01.problem.void-functions/index.ts b/exercises/06.void-and-never/01.problem.void-functions/index.ts index efc8e7c..e20cb72 100644 --- a/exercises/06.void-and-never/01.problem.void-functions/index.ts +++ b/exercises/06.void-and-never/01.problem.void-functions/index.ts @@ -1,18 +1,20 @@ // Logging System // Functions that perform side effects return void -// 🐨 Create `logInfo` that takes a message and logs it with "[INFO]" prefix -// πŸ’° Functions that don't return values have a special type: `void` +// 🐨 Create `logInfo(message: string): void` +// πŸ’° Log with an "[INFO]" prefix, e.g. [INFO] Application started -// 🐨 Create `logError` that takes a message and logs it with "[ERROR]" prefix +// 🐨 Create `logError(message: string): void` +// πŸ’° Log with an "[ERROR]" prefix -// 🐨 Create `logWithTimestamp` that takes a message and logs it with timestamp -// πŸ’° Include the current time in the log using `new Date().toISOString()` +// 🐨 Create `logWithTimestamp(message: string): void` +// πŸ’° Log with the current time as an ISO timestamp in brackets, then the message +// Example shape: [2024-01-15T12:00:00.000Z] User logged in // βœ… Test your functions // logInfo('Application started') // logError('Connection failed') // logWithTimestamp('User logged in') -// 🐨 Export your functions so we can verify your work +// 🐨 Export logInfo, logError, and logWithTimestamp // export { logInfo, logError, logWithTimestamp } diff --git a/exercises/06.void-and-never/02.problem.never-type/README.mdx b/exercises/06.void-and-never/02.problem.never-type/README.mdx index d7dd21c..0aac4dc 100644 --- a/exercises/06.void-and-never/02.problem.never-type/README.mdx +++ b/exercises/06.void-and-never/02.problem.never-type/README.mdx @@ -14,13 +14,29 @@ function fail(message: string): never { TypeScript uses this to mark code paths that can't continue. A `never` function is one that always throws or exits early. -🐨 Open and: +🐨 Open and create these exported functions: -1. Create a `throwError` function that throws and returns `never` -2. Create a `parseNumber` function that converts a string to a number, using - `throwError("Invalid number")` if the input can't be parsed -3. Create an `ensurePositive` function that returns the number if positive, or - uses `throwError("Number must be positive")` if negative +1. `throwError(message: string): never` β€” always throws an error using the given + message +2. `parseNumber(value: string): number` β€” turn a string into a number; if the + value cannot be parsed, call `throwError` with the exact message + `Invalid number`; otherwise return the number +3. `ensurePositive(value: number): number` β€” return the number when it is zero + or positive; if it is negative, call `throwError` with the exact message + `Number must be positive` + +## Required exports + +`throwError`, `parseNumber`, `ensurePositive` + +## Completion criteria + +- `throwError('Test error')` throws with message `Test error` +- `parseNumber('42')` returns `42` +- `parseNumber('not-a-number')` throws with message `Invalid number` +- `ensurePositive(5)` returns `5` +- `ensurePositive(0)` returns `0` (zero is allowed) +- `ensurePositive(-1)` throws with message `Number must be positive` The key learning here is that `parseNumber` and `ensurePositive` should @@ -29,9 +45,4 @@ is one that always throws or exits early. `never`-returning function call is unreachable. - - `Number(value)` converts a string to a number. If the string can't be parsed, - it returns `NaN` (Not a Number). Check for `NaN` using `Number.isNaN(result)`. - - πŸ“œ [TypeScript Handbook - never](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#the-never-type) diff --git a/exercises/06.void-and-never/02.problem.never-type/index.ts b/exercises/06.void-and-never/02.problem.never-type/index.ts index f3a8cae..ff322c9 100644 --- a/exercises/06.void-and-never/02.problem.never-type/index.ts +++ b/exercises/06.void-and-never/02.problem.never-type/index.ts @@ -1,22 +1,20 @@ // Understanding the Never Type // Functions that never return -// 🐨 Create `throwError` that takes a message and throws -// It should return `never` because it always throws +// 🐨 Create `throwError(message: string): never` +// It should always throw an Error with that message -// 🐨 Create `parseNumber` that: -// - Takes a string -// - Converts it to a number with Number(...) -// - Throws if the result is NaN +// 🐨 Create `parseNumber(value: string): number` +// - Return the parsed number for valid numeric strings +// - Call throwError('Invalid number') when the value cannot be parsed -// 🐨 Create `ensurePositive` that: -// - Takes a number -// - Throws if the number is negative -// - Returns the number if it's valid +// 🐨 Create `ensurePositive(value: number): number` +// - Return the number when it is zero or positive +// - Call throwError('Number must be positive') when it is negative // βœ… Test // console.log(parseNumber('42')) // console.log(ensurePositive(5)) -// 🐨 Export your functions so we can verify your work +// 🐨 Export throwError, parseNumber, and ensurePositive // export { throwError, parseNumber, ensurePositive } diff --git a/exercises/06.void-and-never/02.solution.never-type/index.test.ts b/exercises/06.void-and-never/02.solution.never-type/index.test.ts index 3ee9c77..b20fcdc 100644 --- a/exercises/06.void-and-never/02.solution.never-type/index.test.ts +++ b/exercises/06.void-and-never/02.solution.never-type/index.test.ts @@ -13,7 +13,7 @@ await test('throwError should throw an error', () => { assert.throws( () => solution.throwError('Test error'), { message: 'Test error' }, - '🚨 throwError should throw an error with the provided message - use throw new Error()', + '🚨 throwError should throw an error with the provided message', ) }) @@ -28,7 +28,7 @@ await test('parseNumber should parse valid numbers', () => { assert.strictEqual( solution.parseNumber('42'), 42, - '🚨 parseNumber("42") should return 42 - use Number(...) to parse the value', + '🚨 parseNumber("42") should return 42', ) }) diff --git a/extra/muffin-shop-checkout/README.mdx b/extra/muffin-shop-checkout/README.mdx index 1950827..03f2642 100644 --- a/extra/muffin-shop-checkout/README.mdx +++ b/extra/muffin-shop-checkout/README.mdx @@ -6,31 +6,37 @@ clean summary for customers. πŸ“œ This example sticks to the skills from the workshop: numbers, strings, booleans, variables, functions, if/else, switch statements, and loops. -🐨 Open and complete the following tasks: - -1. Build the divider string with a loop. -2. Calculate `subtotal`. -3. Implement `calculateDiscount`. -4. Implement `calculateTax`. -5. Implement `calculateTip`. -6. Implement `calculatePickupFee` with a switch statement. -7. Set `pickupLabel` with an if/else. -8. Set `memberMessage` with an if/else. -9. Calculate `total`. -10. Make sure the receipt prints with `console.log`. +🐨 Open and complete the helpers and values +below. Fixture inputs (`muffinCount`, prices, `taxRate`, `tipPercent`, +`isMember`, `pickupMethod`, and so on) are already in the file. -πŸ’° Flip `isMember` to see the discount and message change. -πŸ’° Try `pickupMethod` as `curbside` or `delivery` to test the switch logic. - -## Run the example +## Business rules -```sh nonumber -npm run start --workspace examples/muffin-shop-checkout -``` +- **Divider lines**: `buildDivider` builds the `=` / `-` banner lines by + repeating a character to a given length. +- **Money display**: `formatMoney` formats an amount with a leading `$` (for + example `3.25` displays as `$3.25`, and `4` as `$4`). +- **Subtotal**: sum of each line item (quantity Γ— unit price for muffins and + scones). +- **Member discount**: members get 10% off when the subtotal is at least `$15`; + otherwise the discount is `$0`. +- **Tax**: applied to the amount after the discount, using `taxRate`. +- **Tip**: applied to the post-discount subtotal plus tax, using `tipPercent`. +- **Pickup fee** (use a `switch` on `pickupMethod`): + - `counter` β†’ `$0` + - `curbside` β†’ `$3` + - `delivery` β†’ `$7` +- **Pickup label**: show `FREE` when the fee is `$0`; otherwise show the fee with + `formatMoney`. +- **Member message**: `Member discount applied` for members, otherwise + `Join the club for 10% off`. +- **Total**: subtotal, minus discount, plus tax, tip, and pickup fee. +- Print the assembled `receipt` with `console.log`. -## What the output can look like +## Success criteria (default fixtures) -Here is a sample console receipt output: +With the starter defaults (`isMember = true`, `pickupMethod = 'counter'`, etc.), +your printed receipt should match this shape and the sample numbers below: ```text ================================ @@ -51,6 +57,17 @@ Member discount applied ================================ ``` +(Floating-point display may vary slightly; the structure and labels must match.) + +πŸ’° Flip `isMember` to see the discount and message change. +πŸ’° Try `pickupMethod` as `curbside` or `delivery` to test the switch logic. + +## Run the example + +```sh nonumber +npm run start --workspace extra_muffin-shop-checkout +``` + ## Try next - 🐨 Add a `dailySpecialCount` and `dailySpecialPrice`, then include them in the diff --git a/extra/muffin-shop-checkout/index.ts b/extra/muffin-shop-checkout/index.ts index b1d20b7..5789634 100644 --- a/extra/muffin-shop-checkout/index.ts +++ b/extra/muffin-shop-checkout/index.ts @@ -13,44 +13,38 @@ const taxRate = 0.0825 const pickupMethod = 'counter' function buildDivider(char: string, length: number) { - // 🐨 Build and return a divider string by repeating char - // πŸ’° Build the string by repeating the character in a loop + // 🐨 Return a string made by repeating `char` exactly `length` times let line = '' return line } function formatMoney(amount: number) { - // 🐨 Return a string like `$4.5` using a template literal - return `$${amount}` + // 🐨 Format amount with a leading "$" (e.g. 3.25 β†’ "$3.25", 4 β†’ "$4") + return '$0' } function calculateDiscount(subtotal: number, member: boolean) { - // 🐨 If the customer is a member and subtotal is at least 15, - // return 10% of subtotal. Otherwise return 0. + // 🐨 Members get 10% off when subtotal is at least 15; otherwise 0 return 0 } function calculateTax(subtotal: number, rate: number) { - // 🐨 Return subtotal multiplied by rate + // 🐨 Return the tax for this amount and rate return 0 } function calculateTip(totalBeforeTip: number, percent: number) { - // 🐨 Return totalBeforeTip multiplied by percent + // 🐨 Return the tip for this amount and percent return 0 } function calculatePickupFee(method: string) { - // 🐨 Use a switch statement to return: - // 'counter' -> 0 - // 'curbside' -> 3 - // 'delivery' -> 7 + // 🐨 Use a switch: counter β†’ 0, curbside β†’ 3, delivery β†’ 7 return 0 } let subtotal = 0 -// 🐨 Set subtotal using item counts and prices -// πŸ’° Use the counts and prices to compute the subtotal +// 🐨 Set subtotal from the muffin and scone counts and prices const discount = calculateDiscount(subtotal, isMember) const taxableAmount = subtotal - discount @@ -59,15 +53,14 @@ const tip = calculateTip(taxableAmount + tax, tipPercent) const pickupFee = calculatePickupFee(pickupMethod) let pickupLabel = '' -// 🐨 If pickupFee is 0, set pickupLabel to 'FREE' -// otherwise set it to formatMoney(pickupFee) +// 🐨 FREE when pickupFee is 0; otherwise formatMoney(pickupFee) let memberMessage = '' -// 🐨 If isMember is true, set memberMessage to 'Member discount applied' -// otherwise set it to 'Join the club for 10% off' +// 🐨 Members: 'Member discount applied' +// Guests: 'Join the club for 10% off' let total = 0 -// 🐨 Set total using subtotal, discount, tax, tip, and pickupFee +// 🐨 Combine subtotal, discount, tax, tip, and pickupFee into the final total const header = buildDivider('=', 32) const divider = buildDivider('-', 32) diff --git a/extra/muffin-shop-dashboard/README.mdx b/extra/muffin-shop-dashboard/README.mdx index 2bb73d7..79d1f0c 100644 --- a/extra/muffin-shop-dashboard/README.mdx +++ b/extra/muffin-shop-dashboard/README.mdx @@ -7,22 +7,50 @@ double-check totals before handing it off. for you. You only need the workshop skills: numbers, strings, booleans, variables, functions, if/else, switch statements, loops, and `never`. -🐨 Open and complete the following tasks: - -1. Format money with a template literal. -2. Add the `(GF)` label for gluten-free items. -3. Sum the subtotal with a loop. -4. Apply the member discount. -5. Calculate tax and tip. -6. Calculate the final total. -7. Return the pickup fee with a switch statement. -8. Return the pickup label with a switch statement. -9. Format the special note when it's empty. -10. Log the ready message. -11. Implement `assertNever`. - -πŸ’° Toggle `memberStatus` or `pickupMethod` in to -see different outputs. +🐨 Open and implement the exported +helpers. Function signatures are already in the file. + +## Business rules + +- **Money display**: `formatMoney` formats an amount with a leading `$` (for + example `4.5` displays as `$4.5`). +- **Line items**: `buildLineItemText` shows `quantity x name`, and appends + ` (GF)` (leading space) when the item is gluten-free. Examples: + `2 x Blueberry Muffin`, `1 x Oatberry Muffin (GF)`. +- **Subtotal**: sum of each item’s price Γ— quantity (use a loop). +- **Member discount**: status `'member'` gets 10% off when the subtotal is at + least `$20`; otherwise `$0`. +- **Tax / tip**: tax uses the taxable amount and rate; tip uses the amount before + tip and the tip percent. +- **Total**: subtotal, minus discount, plus tax, tip, and pickup fee. +- **Pickup fee** (switch): `counter` β†’ `$0`, `curbside` β†’ `$3`, `delivery` β†’ `$7`. +- **Pickup label** (switch): `Counter pickup`, `Curbside pickup`, or + `Delivery dropoff`. Use `assertNever` for impossible cases. +- **Notes**: `null` or an empty string becomes `No special notes`; otherwise keep + the note. +- **Ready log**: `logOrderReady` is a `void` function that logs + `Order ready for `. +- **`assertNever`**: throw so TypeScript knows that branch cannot continue + (include the unexpected value in the error). + +## Success criteria + +- The dashboard in renders without runtime + errors once the helpers are implemented +- With the default app fixtures (`member`, `curbside`, gluten-free items, empty + note), you should see: + - Line items including a `(GF)` suffix where appropriate + - Pickup label `Curbside pickup` and a pickup fee of `$3` + - Special note text `No special notes` + - Console log: `Order ready for Avery` +- Toggle `memberStatus` or `pickupMethod` in + and confirm labels/fees/discounts update + +## Run the example + +```sh nonumber +npm run dev --workspace extra_muffin-shop-dashboard +``` ## Try next diff --git a/extra/muffin-shop-dashboard/src/muffin-utils.ts b/extra/muffin-shop-dashboard/src/muffin-utils.ts index 99c2cb4..5ab4a11 100644 --- a/extra/muffin-shop-dashboard/src/muffin-utils.ts +++ b/extra/muffin-shop-dashboard/src/muffin-utils.ts @@ -9,39 +9,35 @@ type MemberStatus = 'member' | 'guest' type PickupMethod = 'counter' | 'curbside' | 'delivery' function formatMoney(amount: number) { - // 🐨 Return a string like `$4.5` using a template literal - // πŸ’° Use a template literal to format the amount with a $ prefix + // 🐨 Format amount with a leading "$" (e.g. 4.5 β†’ "$4.5") return '$0' } function buildLineItemText(item: OrderItem) { - // 🐨 Return a string like `2 x Blueberry Muffin (GF)` - // πŸ’° Build the string from the item fields - let glutenFreeLabel = '' - // 🐨 If item.isGlutenFree is true, set glutenFreeLabel to ' (GF)' - return `${item.quantity} x ${item.name}${glutenFreeLabel}` + // 🐨 Return "quantity x name", plus " (GF)" when the item is gluten-free + // Examples: "2 x Blueberry Muffin", "1 x Oatberry Muffin (GF)" + void item + return '' } function calculateSubtotal(items: OrderItem[]) { - // 🐨 Use a for loop to add each item total to subtotal - // πŸ’° Multiply each item's price by its quantity + // 🐨 Loop items and sum each line total (price Γ— quantity) let subtotal = 0 return subtotal } function calculateDiscount(subtotal: number, status: MemberStatus) { - // 🐨 If status is 'member' and subtotal is at least 20, - // return 10% of subtotal. Otherwise return 0. + // 🐨 Members get 10% off when subtotal is at least 20; otherwise 0 return 0 } function calculateTax(taxableAmount: number, rate: number) { - // 🐨 Return taxableAmount multiplied by rate + // 🐨 Return the tax for this amount and rate return 0 } function calculateTip(totalBeforeTip: number, percent: number) { - // 🐨 Return totalBeforeTip multiplied by percent + // 🐨 Return the tip for this amount and percent return 0 } @@ -52,40 +48,35 @@ function calculateTotal( tip: number, pickupFee: number, ) { - // 🐨 Return the final total using subtotal, discount, tax, tip, and pickupFee + // 🐨 Combine subtotal, discount, tax, tip, and pickupFee into the final total return 0 } function getPickupFee(method: PickupMethod) { - // 🐨 Use a switch statement to return: - // 'counter' -> 0 - // 'curbside' -> 3 - // 'delivery' -> 7 + // 🐨 Switch: counter β†’ 0, curbside β†’ 3, delivery β†’ 7 return 0 } function getPickupLabel(method: PickupMethod) { - // 🐨 Return a label for the pickup method: - // 'counter' -> 'Counter pickup' - // 'curbside' -> 'Curbside pickup' - // 'delivery' -> 'Delivery dropoff' - // πŸ’° Use a switch statement and handle the unexpected case + // 🐨 Switch labels: + // counter β†’ 'Counter pickup' + // curbside β†’ 'Curbside pickup' + // delivery β†’ 'Delivery dropoff' + // πŸ’° Handle impossible cases with assertNever return method } function formatNote(note: string | null) { - // 🐨 If note is null or an empty string, return 'No special notes' - // otherwise return the note + // 🐨 null or '' β†’ 'No special notes'; otherwise return the note return note ?? '' } function logOrderReady(customer: string): void { - // 🐨 Use console.log to print `Order ready for ${customer}` + // 🐨 Log: Order ready for } function assertNever(value: never): never { - // 🐨 Throw an error so TypeScript knows this never happens - // πŸ’° Throw an Error that mentions the unexpected value + // 🐨 Throw an Error that includes the unexpected value throw new Error('Unhandled case') }