Skip to content

Commit

Permalink
Add Lab: Group Discount (Section 1: Composing Types: Part II)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonplend committed Sep 3, 2024
1 parent f1ca41d commit 205e507
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 0 deletions.
24 changes: 24 additions & 0 deletions 01-composing-types-part-2/lab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Lab: Group Discount 🛍️

> **Section 1: Composing Types: Part II**
We're trying to group the discounts that we offer in our online store, but we're
having a tough time creating the types for these groups. Can you help us?!

## Requirements

We got stuck creating the `GroupedDiscounts` type, so it currently allows for `any`
type of value.

1. Change the `GroupedDiscounts` type into a mapped type that allows for grouping
discounts by their `kind` property.
2. Test that your code runs correctly with `npx tsx index.ts`.

### Extra Credit

The `DiscountBase` has a wide type of `string` for the `code` property, but we'd
like to ensure that the discount code for each kind of discount matches a specific
format.

Use the existing `code` values to help you establish the formats, and then create
template literal types to enforce a specific format for each kind of discount.
93 changes: 93 additions & 0 deletions 01-composing-types-part-2/lab/solution/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
type DiscountBase = {
description: string;
};

type PercentageDiscount = DiscountBase & {
kind: "percentage";
code: `PERCENT_OFF_${number}`;
percentage: number;
};

type AmountDiscount = DiscountBase & {
kind: "amount";
code: `AMOUNT_OFF_${number}`;
amount: number;
};

type QuantityDiscount = DiscountBase & {
kind: "quantity";
code: `BUY_${number}_GET_${number}_FREE`;
quantity: number;
free: number;
};

type Discount = PercentageDiscount | AmountDiscount | QuantityDiscount;

// -- Discounts --

const discounts: Discount[] = [
{
code: "PERCENT_OFF_10",
description: "10% off",
kind: "percentage",
percentage: 10,
},
{
code: "AMOUNT_OFF_5",
description: "$5 off",
kind: "amount",
amount: 5,
},
{
code: "PERCENT_OFF_30",
description: "30% off",
kind: "percentage",
percentage: 30,
},
{
kind: "quantity",
code: "BUY_1_GET_1_FREE",
description: "Buy 1 get 1 free",
quantity: 1,
free: 1,
},
{
kind: "amount",
code: "AMOUNT_OFF_15",
description: "$15 off",
amount: 15,
},
{
kind: "quantity",
code: "BUY_3_GET_1_FREE",
description: "Buy 3 get 1 free",
quantity: 3,
free: 1,
},
];

// -- Grouped discounts --

type GroupedDiscounts = {
[Key in Discount["kind"]]?: Discount[];
};

// Alternative `GroupedDiscounts` type using built-in utility types.
{
type GroupedDiscounts = Partial<Record<Discount["kind"], Discount[]>>;
}

function groupDiscounts(discounts: Discount[]): GroupedDiscounts {
const groups: GroupedDiscounts = {};

for (let discount of discounts) {
groups[discount.kind] = groups[discount.kind] ?? [];
groups[discount.kind]?.push(discount);
}

return groups;
}

const groupedDiscounts = groupDiscounts(discounts);

console.log(groupedDiscounts);
3 changes: 3 additions & 0 deletions 01-composing-types-part-2/lab/solution/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@total-typescript/tsconfig/tsc/no-dom/app"
}
84 changes: 84 additions & 0 deletions 01-composing-types-part-2/lab/start/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
type DiscountBase = {
code: string;
description: string;
};

type PercentageDiscount = DiscountBase & {
kind: "percentage";
percentage: number;
};

type AmountDiscount = DiscountBase & {
kind: "amount";
amount: number;
};

type QuantityDiscount = DiscountBase & {
kind: "quantity";
quantity: number;
free: number;
};

type Discount = PercentageDiscount | AmountDiscount | QuantityDiscount;

// -- Discounts --

const discounts: Discount[] = [
{
code: "PERCENT_OFF_10",
description: "10% off",
kind: "percentage",
percentage: 10,
},
{
code: "AMOUNT_OFF_5",
description: "$5 off",
kind: "amount",
amount: 5,
},
{
code: "PERCENT_OFF_30",
description: "30% off",
kind: "percentage",
percentage: 30,
},
{
kind: "quantity",
code: "BUY_1_GET_1_FREE",
description: "Buy 1 get 1 free",
quantity: 1,
free: 1,
},
{
kind: "amount",
code: "AMOUNT_OFF_15",
description: "$15 off",
amount: 15,
},
{
kind: "quantity",
code: "BUY_3_GET_1_FREE",
description: "Buy 3 get 1 free",
quantity: 3,
free: 1,
},
];

// -- Grouped discounts --

type GroupedDiscounts = any;

function groupDiscounts(discounts: Discount[]): GroupedDiscounts {
const groups: GroupedDiscounts = {};

for (let discount of discounts) {
groups[discount.kind] = groups[discount.kind] ?? [];
groups[discount.kind]?.push(discount);
}

return groups;
}

const groupedDiscounts = groupDiscounts(discounts);

console.log(groupedDiscounts);
3 changes: 3 additions & 0 deletions 01-composing-types-part-2/lab/start/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@total-typescript/tsconfig/tsc/no-dom/app"
}

0 comments on commit 205e507

Please sign in to comment.