๐ŸŽ“ A1Learner
๐Ÿ”

TypeScript Project: Typed Cart

The typed cart project builds a small shop program from the types in this course. One file holds the product type, a generic finder and a printed receipt.

The Product interface

The interface states the shape of one product. The object below matches it field for field.

interface Product {
  id: number;
  name: string;
  price: number;
}

const product: Product = { id: 1, name: "Notebook", price: 4 };
console.log(product.name, product.price);

A generic finder

The finder accepts any item type with a numeric id. The constraint states that one requirement.

interface Product {
  id: number;
  name: string;
  price: number;
}

function findById<T extends { id: number }>(items: T[], id: number): T | undefined {
  return items.find((item) => item.id === id);
}

const products: Product[] = [
  { id: 1, name: "Notebook", price: 4 },
  { id: 2, name: "Pen", price: 2 },
];

const found = findById(products, 2);
if (found) {
  console.log(found.name);
} else {
  console.log("not found");
}

A draft and a status

A Partial draft holds one field of a product. The cart status variable accepts only the two words in its union.

interface Product {
  id: number;
  name: string;
  price: number;
}

const draft: Partial<Product> = { name: "Pencil" };
let cartStatus: "open" | "paid" = "open";
console.log(draft);
console.log(cartStatus);

Example

interface Product {
  id: number;
  name: string;
  price: number;
}

const products: Product[] = [
  { id: 1, name: "Notebook", price: 4 },
  { id: 2, name: "Pen", price: 2 },
  { id: 3, name: "Pencil", price: 1 },
];

function findById<T extends { id: number }>(items: T[], id: number): T | undefined {
  return items.find((item) => item.id === id);
}

function totalPrice(items: Product[]): number {
  let total = 0;
  for (const item of items) {
    total += item.price;
  }
  return total;
}

function printReceipt(items: Product[], state: "open" | "paid"): void {
  if (state === "paid") {
    console.log("Receipt: paid in full");
  } else {
    console.log("Receipt: payment due");
  }
  console.log("Items: " + items.length);
}

let cartStatus: "open" | "paid" = "paid";
const found = findById(products, 2);
if (found) {
  console.log(found.name);
}
console.log("Total: " + totalPrice(products));
printReceipt(products, cartStatus);

Key points

  • The Product interface states the fields every product holds
  • The generic finder works for any item type with a numeric id
  • The total adds the price of each product in the array
  • Narrowing the status union picks the right receipt line
  • A Partial draft can hold part of a product while it is built

In this example, the products array holds three values of the Product type. findById searches the array with its generic constraint and finds the pen. totalPrice adds the three prices to 7. printReceipt narrows the status union and prints the paid line, then the item count.

Note

Every value in the program carries a type, so a wrong field fails before the program runs

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท TypeScript Playground

Exercise

What does the constraint on findById require of the item type?