저장을 습관화

TypeScript 연습 - 도서관 프로그램 만들기 본문

공부/TypeScript

TypeScript 연습 - 도서관 프로그램 만들기

ctrs 2023. 8. 1. 23:49

작업 환경: Windows 10, VSC

 

작업 목표: 도서관 관리 프로그램

주요 기능 - 권한:

도서 추가 기능 - 사서

도서 삭제 기능 - 사서

도서 대여 기능 - 유저

도서 반납 기능 - 유저

 

 

작업 기록

1. 환경 구축

$ npm init -y

$ tsc --init --rootDir ./src --outDir ./dist --esModuleInterop --module commonjs --strict true --allowJS true --checkJS true

--rootDir: 소스 파일이 들어가는 경로를 명시적으로 지정함
이번에는 ./src 디렉토리에 넣겠다고 하였음

-- outDir: 컴파일된 파일이 tsc로 되면 TS파일이 JS 파일로 나올것임
여기서는 ./dist 디렉토리에 들어가게끔 하였음

--esModuleInterop: require 구문을 사용해서 가져오던 CommonJS 방식의 모듈을 es모듈 방식의 import 구문으로 가져올 수 있게 함

 

package.json, tsconfig.json 파일 생성 확인

 

package.json 파일 내용 수정

 

{
...(생략)...
"scripts": {
    "start": "tsc && node ./dist/index.js",
    "build": "tsc --build",
    "clean": "tsc --build --clean"
  },
...(생략)...
}

 

2. /src/index.ts 파일 생성

// 역할 enum
enum Role {
  LIBRARIAN, // 사서
  MEMBER, // 멤버
}

// 유저 추상 클래스
abstract class User {
  constructor(public name: string, public age: number) {}
  abstract getRole(): Role;
}

// 멤버 클래스
class Member extends User {
  constructor(name: string, age: number) {
    super(name, age);
  }
  getRole(): Role {
    return Role.MEMBER;
  }
}

// 사서 클래스
class Librarian extends User {
  constructor(name: string, age: number) {
    super(name, age);
  }
  getRole(): Role {
    return Role.LIBRARIAN;
  }
}

// 책 클래스
class Book {
  constructor(
    public title: string,
    public author: string,
    public publishedDate: Date
  ) {}
}

// 책 관리 인터페이스, 도서 목록 조회, 추가, 삭제, 대여, 반납 기능
interface RentManager {
  getBooks(): Book[]; // 도서관의 현재 도서 목록을 확인하는 함수
  addBook(user: User, book: Book): void; // 사서가 도서관에 새로운 도서를 입고할 때 호출하는 함수
  removeBook(user: User, book: Book): void; // 사서가 도서관에서 도서를 폐기할 때 호출하는 함수
  rentBook(user: Member, book: Book): void; // 사용자가 책을 빌릴 때 호출하는 함수
  returnBook(user: Member, book: Book): void; // 사용자가 책을 반납할 때 호출하는 함수
}

// 도서관 클래스 구현
class Library implements RentManager {
  private books: Book[] = [];
  // rentedBooks는 유저의 대여 이력을 관리해요!
  private rentedBooks: Map<string, Book> = new Map<string, Book>();

  getBooks(): Book[] {
    // 깊은 복사를 하여 외부에서 books를 수정하는 것을 방지합니다.
    return JSON.parse(JSON.stringify(this.books));
  }

  addBook(user: User, book: Book): void {
    if (user.getRole() !== Role.LIBRARIAN) {
      console.log("사서만 도서를 추가할 수 있습니다.");
      return;
    }

    this.books.push(book);
  }

  removeBook(user: User, book: Book): void {
    if (user.getRole() !== Role.LIBRARIAN) {
      console.log("사서만 도서를 삭제할 수 있습니다.");
      return;
    }

    const index = this.books.indexOf(book);
    if (index !== -1) {
      this.books.splice(index, 1);
    }
  }

  rentBook(user: User, book: Book): void {
    if (user.getRole() !== Role.MEMBER) {
      console.log("유저만 도서를 대여할 수 있습니다.");
      return;
    }

    if (this.rentedBooks.has(user.name)) {
      console.log(
        `${user.name}님은 이미 다른 책을 대여중이라 빌릴 수 없습니다.`
      );
    } else {
      this.rentedBooks.set(user.name, book);
      console.log(`${user.name}님이 [${book.title}] 책을 빌렸습니다.`);
    }
  }

  returnBook(user: User, book: Book): void {
    if (user.getRole() !== Role.MEMBER) {
      console.log("유저만 도서를 반납할 수 있습니다.");
      return;
    }

    if (this.rentedBooks.get(user.name) === book) {
      this.rentedBooks.delete(user.name);
      console.log(`${user.name}님이 [${book.title}] 책을 반납했어요!`);
    } else {
      console.log(`${user.name}님은 [${book.title}] 책을 빌린적이 없어요!`);
    }
  }
}

function main() {
  const myLibrary = new Library();
  const librarian = new Librarian("ctrs", 29);
  const member1 = new Member("testCust", 30);
  const member2 = new Member("booker", 28);

  const book = new Book("TypeScript 문법 종합반", "강창민", new Date());
  const book2 = new Book("금쪽이 훈육하기", "오은영", new Date());
  const book3 = new Book("요식업은 이렇게!", "백종원", new Date());

  myLibrary.addBook(librarian, book);
  myLibrary.addBook(librarian, book2);
  myLibrary.addBook(librarian, book3);
  const books = myLibrary.getBooks();
  console.log("대여할 수 있는 도서 목록:", books);

  myLibrary.rentBook(member1, book);
  myLibrary.rentBook(member2, book2);

  myLibrary.returnBook(member1, book);
  myLibrary.returnBook(member2, book2);
}

main();

 

 

3. 컴파일

$ npm run build

> 04.-class@1.0.0 build
> tsc --build

 

 

4. 실행

$ npm run start

> 04.-class@1.0.0 start
> tsc && node ./dist/index.js

대여할 수 있는 도서 목록: [
  {
    title: 'TypeScript 문법 종합반',
    author: '강창민',
    publishedDate: '2023-08-01T14:49:02.879Z'
  },
  {
    title: '금쪽이 훈육하기',
    author: '오은영',
    publishedDate: '2023-08-01T14:49:02.879Z'
  },
  {
    title: '요식업은 이렇게!',
    author: '백종원',
    publishedDate: '2023-08-01T14:49:02.879Z'
  }
]
testCust님이 [TypeScript 문법 종합반] 책을 빌렸습니다.
booker님이 [금쪽이 훈육하기] 책을 빌렸습니다.
testCust님이 [TypeScript 문법 종합반] 책을 반납했어요!
booker님이 [금쪽이 훈육하기] 책을 반납했어요!