Skip to content

src/index.ts โ€‹

From TS basics exercise (ts-intro) ยท original: si-679-f-26-ts-basics-jessicadonoho/src/index.ts ยท all files in this project

ts
// ============================================================
// TypeScript Intro Exercise: Book Catalog
// ============================================================
// This is a small, working JavaScript program. Your job is to
// translate it into TypeScript by working through the six
// numbered TODOs below, in order. Each TODO names the TS
// feature it's meant to have you practice.
//
// Workflow:
//   1. Copy this file to src/index.ts
//   2. Run `npm run typecheck` and read the errors TS gives you
//   3. Work through the TODOs one at a time
//   4. Re-run `npm run typecheck` until it's clean
//   5. Run `npm run dev` (or `npm run build && npm start`) and
//      confirm the console output matches README.md exactly
// ============================================================

// ---- TODO (1): Interface ---------------------------------------
// After reading through the cocde, define an interface named `Book` 
// describing the shape used below (title, author, year, status).
// You will need this for several subsequent steps.
interface Book {
    title:string;
    author:string;
    year:number;
    status:unknown;
}

// ---- TODO (2): Explicit type declaration -------------------
// Give `catalog` an explicit type annotation instead of relying
// on inference. See how it's used below to choose the appropriate
// type.
const catalog:Book[] = [];

// ---- TODO (3): Enum -------------------------------------------
// Replace these three string constants with a TypeScript enum
// named `BookStatus`, then update the book objects below (and
// every function that compares against a status) to use it.

enum BookStatus {
    STATUS_AVAILABLE = "available",
    STATUS_CHECKED_OUT = "checked-out",
    STATUS_LOST = "lost",
}

// const STATUS_AVAILABLE = "available";
// const STATUS_CHECKED_OUT = "checked-out";
// const STATUS_LOST = "lost";

// ---- TODO (4): Function signatures ------------------------------
// Add parameter types and a return type to each function below.

function addBook(catalog:Book[], book:Book):Book[] {
  catalog.push(book);
  return catalog;
}

function findBookByTitle(catalog:Book[], title:string):Book | undefined{
  return catalog.find((book) => book.title === title);
}

function checkoutBook(catalog:Book[], title:string):boolean {
  const book = findBookByTitle(catalog, title);
  if (!book || book.status !== BookStatus.STATUS_AVAILABLE) {
    return false;
  }
  book.status = BookStatus.STATUS_CHECKED_OUT;
  return true;
}

function returnBook(catalog:Book[], title:string):boolean {
  const book = findBookByTitle(catalog, title);
  if (!book) {
    return false;
  }
  book.status = BookStatus.STATUS_AVAILABLE;
  return true;
}

// ---- TODO (5): Type alias ---------------------------------------
// `findBooksBy` accepts EITHER an author name (string) OR a
// publication year (number). Define a type alias, e.g.
//   type MyTypeAlias = type1 | type2;
// and use it as the type of the `filter` parameter.

type MyFilterType = string | number;

function findBooksBy(catalog:Book[], filter:MyFilterType) {
  if (typeof filter === "number") {
    return catalog.filter((book) => book.year === filter);
  }
  return catalog.filter((book) => book.author === filter);
}

// ---- TODO (6): Basic generics -------------------------------------
// Make `getFirstItem` generic so it works for an array of any
// type, with TypeScript inferring the correct return type
// instead of you writing `any` anywhere.
// hint: you will need to use TypeScript's <Generic> features.

function getFirstItem<Type>(items: Array<Type>):Type {
  return items[0];
}

// ============================================================
// Demo โ€” be careful when editing below this line. You will
// need to make changes based on changes you make above, but 
// do not change the output as this will mess up the autograder.
// 
// This is the part that produces the console output documented 
// in README.md.
// ============================================================

addBook(catalog, { title: "The Hobbit", author: "J.R.R. Tolkien", year: 1937, status: BookStatus.STATUS_AVAILABLE });
addBook(catalog, { title: "Dune", author: "Frank Herbert", year: 1965, status: BookStatus.STATUS_AVAILABLE });
addBook(catalog, { title: "Foundation", author: "Isaac Asimov", year: 1951, status: BookStatus.STATUS_LOST });
addBook(catalog, { title: "Children of Time", author: "Adrian Tchaikovsky", year: 2015, status: BookStatus.STATUS_AVAILABLE });

console.log("== Full catalog ==");
catalog.forEach((book) => console.log(`- ${book.title} (${book.year}) by ${book.author} [${book.status}]`));

console.log("\n== Checking out 'Dune' ==");
console.log("Success:", checkoutBook(catalog, "Dune"));
console.log("Success (already checked out):", checkoutBook(catalog, "Dune"));

console.log("\n== Books by Frank Herbert ==");
findBooksBy(catalog, "Frank Herbert").forEach((book) => console.log(`- ${book.title}`));

console.log("\n== Books from 1937 ==");
findBooksBy(catalog, 1937).forEach((book) => console.log(`- ${book.title}`));

console.log("\n== First book in the catalog ==");
console.log(getFirstItem(catalog).title);

console.log("\n== Returning 'Dune' ==");
returnBook(catalog, "Dune");
console.log(findBookByTitle(catalog, "Dune")!.status);