๋ฉ”์ธ ์ฝ˜ํ…์ธ ๋กœ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋…ธํŠธ ๋ชฉ๋ก

๐Ÿ”ง lib/books.ts ํ•œ ์ค„์”ฉ ๋งŒ๋“ค๊ธฐ โ€” CLI ๋กœ ํ™•์ธํ•˜๋ฉฐ ๋ฐฐ์šฐ๊ธฐ

๊น€์„ฑ๋ฐ•590
๋ชฉ์ฐจ11

์ด ๊ธ€์˜ ๋ชฉ์ 

book-api-tutorial ๋ณธ ํŠœํ† ๋ฆฌ์–ผ(TUTORIAL.md)์˜ STEP 2 ์—์„œ lib/books.ts ๋ฅผ ํ•œ ๋ฒˆ์— ๋ณด์—ฌ์คฌ์–ด์š”. ์งง์€ ํŒŒ์ผ์ด์ง€๋งŒ ์ฒ˜์Œ ๋ณด๋ฉด ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๋ฌธ๋ฒ•์ด ํ•œ๊บผ๋ฒˆ์— ๋‚˜์˜ต๋‹ˆ๋‹ค.

  • Omit<Book, "id"> ๊ฐ™์€ ํƒ€์ž…
  • ๋ฐฐ์—ด์˜ find, findIndex
  • globalThis ์บ์ŠคํŒ…
  • ! (non-null assertion)

์ด ๋ณด์กฐ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๊ฐ™์€ ํŒŒ์ผ์„ 6 ๋‹จ๊ณ„ ๋กœ ์ž˜๋ผ์„œ, ๊ฐ ๋‹จ๊ณ„๋งˆ๋‹ค ํ„ฐ๋ฏธ๋„ ์—์„œ ๋™์ž‘์„ ์ง์ ‘ ํ™•์ธํ•˜๋ฉฐ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋งค ๋‹จ๊ณ„ ๋์—๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๋ช…๋ น์ด ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค:

npx tsx scripts/test-books.ts

์ด ํ•œ ์ค„๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์ฝ”๋“œ๋ฅผ ์ฆ‰์‹œ ์‹คํ–‰ํ•ด ๊ฒฐ๊ณผ๋ฅผ ๋ด…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ฑฐ๋‚˜ Next.js ์„œ๋ฒ„๋ฅผ ๋„์šธ ํ•„์š”๊ฐ€ ์—†์–ด์š”.

๐Ÿ“ ์ž‘์—… ์œ„์น˜: book-api-tutorial/ ํ”„๋กœ์ ํŠธ ์•ˆ์—์„œ ๊ทธ๋Œ€๋กœ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค. ๋ณ„๋„ ํด๋”๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„์š”.
๋งˆ์ง€๋ง‰์—” lib/books.ts ๊ฐ€ ๋ณธ ํŠœํ† ๋ฆฌ์–ผ๊ณผ ๋˜‘๊ฐ™์€ ํ˜•ํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.


์‚ฌ์ „ ์ค€๋น„

book-api-tutorial ํด๋”๊ฐ€ ์ด๋ฏธ ์žˆ๋‹ค๋Š” ์ „์ œ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

0-1. TypeScript ์‹คํ–‰ ๋„๊ตฌ ์„ค์น˜

.ts ํŒŒ์ผ์„ ์ปดํŒŒ์ผ ์—†์ด ๋ฐ”๋กœ ์‹คํ–‰ํ•˜๋Š” ๋„๊ตฌ tsx ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

cd book-api-tutorial npm install -D tsx

-D ๋Š” "๊ฐœ๋ฐœ์šฉ ์˜์กด์„ฑ" ์ด๋ผ๋Š” ํ‘œ์‹œ์˜ˆ์š” (์‹ค์ œ ๋นŒ๋“œ์—๋Š” ์•ˆ ๋“ค์–ด๊ฐ).

0-2. scripts ํด๋” ๋งŒ๋“ค๊ธฐ

์ด๋ฒˆ ๋ณด์กฐ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋งŒ ์“ธ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‘˜ ํด๋”์ž…๋‹ˆ๋‹ค.

mkdir scripts

ํด๋” ๊ตฌ์กฐ๋Š” ์ด๋ ‡๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

book-api-tutorial/ โ”œโ”€ app/ โ† ๊ธฐ์กด โ”œโ”€ lib/ โ”‚ โ””โ”€ books.ts โ† ๋‹จ๊ณ„๋ณ„๋กœ ๋‹ค์‹œ ๋งŒ๋“ค ํŒŒ์ผ (์ง€๊ธˆ์€ ์™„์„ฑ๋ณธ ์ƒํƒœ) โ”œโ”€ scripts/ โ† ์ƒˆ๋กœ ์ถ”๊ฐ€ โ”‚ โ””โ”€ test-books.ts โ† CLI ์—์„œ ์‹คํ–‰ํ•  ํ…Œ์ŠคํŠธ โ”œโ”€ package.json โ””โ”€ tsconfig.json โ† @/* ๋ณ„์นญ์ด ์ด๋ฏธ ์„ค์ •๋ผ ์žˆ์–ด์š”

tsx ๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ•œ ๋ฒˆ ํ™•์ธํ•ด ๋ด…๋‹ˆ๋‹ค. ์ž„์‹œ ํŒŒ์ผ์„ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ :

echo 'console.log("hello", { from: "tsx" });' > scripts/smoke.ts npx tsx scripts/smoke.ts # ์ถœ๋ ฅ: hello { from: 'tsx' }

ํ™•์ธ์ด ๋์œผ๋ฉด ์ž„์‹œ ํŒŒ์ผ์€ ์ง€์›๋‹ˆ๋‹ค.

rm scripts/smoke.ts

0-3. ๊ธฐ์กด lib/books.ts ๋ฐฑ์—… (์„ ํƒ)

์ด๋ฏธ ๋ณธ ํŠœํ† ๋ฆฌ์–ผ์„ ๋”ฐ๋ผ ๋งŒ๋“  lib/books.ts ๊ฐ€ ์žˆ๋‹ค๋ฉด, ๋‹จ๊ณ„๋ณ„๋กœ ๋ฎ์–ด์“ฐ๊ฒŒ ๋˜๋‹ˆ ๋ฏธ๋ฆฌ ์–ด๋”˜๊ฐ€์— ๋ณต์‚ฌํ•ด ๋‘๋ฉด ๋งˆ์Œ์ด ํŽธํ•ฉ๋‹ˆ๋‹ค.

cp lib/books.ts /tmp/books-original-backup.ts

์ด์ œ ๋นˆ ๋งˆ์Œ์œผ๋กœ ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.


STEP 1. ํƒ€์ž…๊ณผ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋งŒ

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ˜•ํƒœ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋„ ์—†๊ณ , ๋ฐ์ดํ„ฐ๋งŒ ์žˆ๋Š” ์ƒํƒœ.

๐Ÿ“„ lib/books.ts ์ „์ฒด๋ฅผ ๋‹ค์Œ์œผ๋กœ ๊ต์ฒด:

export type Book = { id: number; title: string; author: string; publishedYear: number; }; export const books: Book[] = [ { id: 1, title: "์–ด๋ฆฐ ์™•์ž", author: "์ƒํ…์ฅํŽ˜๋ฆฌ", publishedYear: 1943 }, { id: 2, title: "๋ฐ๋ฏธ์•ˆ", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919 }, { id: 3, title: "1984", author: "์กฐ์ง€ ์˜ค์›ฐ", publishedYear: 1949 }, ];

๐Ÿ“„ scripts/test-books.ts ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ:

import { books } from "@/lib/books"; console.log("=== ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ==="); console.log(books); console.log("๊ฐœ์ˆ˜:", books.length);

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น export type Book
"Book ์ด๋ผ๋Š” ํƒ€์ž…์„ ๋งŒ๋“ค์—ˆ๊ณ , ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ์–ด" ๋ผ๋Š” ๋œป. ๊ฐ์ฒด ํ•œ ๊ถŒ์˜ ๋ชจ์–‘์„ ๋ฏธ๋ฆฌ ์ ์–ด ๋‘๋ฉด ์˜คํƒ€๊ฐ€ ๋‚ฌ์„ ๋•Œ TypeScript ๊ฐ€ ๋นจ๊ฐ„ ์ค„๋กœ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

๐Ÿ”น export const books: Book[] = [...]

  • export : ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ import ํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค.
  • const : ์ด ๋ณ€์ˆ˜์˜ ์ด๋ฆ„ ์€ ๋‹ค๋ฅธ ๋ฐฐ์—ด๋กœ ๋ชป ๋ฐ”๊พผ๋‹ค. ๋‹จ, ๋ฐฐ์—ด ์•ˆ์˜ ๋‚ด์šฉ์€ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค (books.push(...) ๊ฐ™์€ ๊ฑด ๊ฐ€๋Šฅ).
  • : Book[] : "Book ์˜ ๋ฐฐ์—ด" ์ด๋ผ๋Š” ํƒ€์ž….

๐Ÿ”น import { books } from "@/lib/books"
@/ ๋Š” ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณ„์นญ์ž…๋‹ˆ๋‹ค. book-api-tutorial/tsconfig.json ์— "@/*": ["./*"] ๋กœ ์„ค์ •๋ผ ์žˆ์–ด tsx ๋„ ์ด๋ฅผ ์ธ์‹ํ•ด์š”. ๊ทธ๋ž˜์„œ ์–ด๋””์„œ import ํ•˜๋“  @/lib/books ํ•œ ๊ฐ€์ง€ ํ‘œํ˜„์œผ๋กœ ํ†ต์ผ๋ฉ๋‹ˆ๋‹ค.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts

์ถœ๋ ฅ:

=== ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ === [ { id: 1, title: '์–ด๋ฆฐ ์™•์ž', author: '์ƒํ…์ฅํŽ˜๋ฆฌ', publishedYear: 1943 }, { id: 2, title: '๋ฐ๋ฏธ์•ˆ', author: 'ํ—ค๋ฅด๋งŒ ํ—ค์„ธ', publishedYear: 1919 }, { id: 3, title: '1984', author: '์กฐ์ง€ ์˜ค์›ฐ', publishedYear: 1949 } ] ๊ฐœ์ˆ˜: 3

3๊ถŒ์˜ ์ฑ…์ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ˆ˜ 1: export ๋ฅผ ๋นผ๋จน๊ณ  const books = [...] ๋งŒ ์“ฐ๋ฉด, ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ๋ชป ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์‹ค์ˆ˜ 2: ๊ฐ์ฒด์— ํ•„๋“œ๋ฅผ ๋น ๋œจ๋ฆฌ๋ฉด (์˜ˆ: publishedYear ์—†์ด) ๋นจ๊ฐ„ ์ค„์ด ๊ทธ์–ด์ง‘๋‹ˆ๋‹ค.


STEP 2. getAllBooks() ํ•จ์ˆ˜

๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ export ํ•˜์ง€ ์•Š๊ณ , ํ•จ์ˆ˜๋กœ ํ•œ ๋ฒˆ ๊ฐ์‹ธ์„œ ๋Œ๋ ค์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐฉ์‹์ด ๋ฐ”๋€Œ์–ด๋„(์˜ˆ: globalThis โ†’ DB) ํ•จ์ˆ˜๋งŒ ๊ฐ™์€ ๋ชจ์–‘์ด๋ฉด ๋ฐ”๊นฅ ์ฝ”๋“œ๋Š” ์•ˆ ๋ฐ”๋€Œ์–ด์š”.

๐Ÿ“„ lib/books.ts ๋ฅผ ํ†ต์งธ๋กœ ๊ต์ฒด:

export type Book = { id: number; title: string; author: string; publishedYear: number; }; const books: Book[] = [ { id: 1, title: "์–ด๋ฆฐ ์™•์ž", author: "์ƒํ…์ฅํŽ˜๋ฆฌ", publishedYear: 1943 }, { id: 2, title: "๋ฐ๋ฏธ์•ˆ", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919 }, { id: 3, title: "1984", author: "์กฐ์ง€ ์˜ค์›ฐ", publishedYear: 1949 }, ]; export function getAllBooks(): Book[] { return books; }

๋ฐ”๋€ ๊ณณ: export const books ์˜ export ๋ฅผ ๋–ผ๊ณ , ๋Œ€์‹  getAllBooks() ํ•จ์ˆ˜๋ฅผ export ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“„ scripts/test-books.ts:

import { getAllBooks } from "@/lib/books"; console.log("=== ๋ชจ๋“  ์ฑ… ==="); console.log(getAllBooks()); console.log("๊ฐœ์ˆ˜:", getAllBooks().length);

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น export function getAllBooks(): Book[] { ... }

  • ํ•จ์ˆ˜ ์ด๋ฆ„: getAllBooks
  • ๋ฐ˜ํ™˜ ํƒ€์ž…: Book[] โ€” Book ๋ฐฐ์—ด
  • ๋ชธ์ฒด: return books โ€” ๋ชจ๋“ˆ ์•ˆ์˜ books ๋ฅผ ๊ทธ๋Œ€๋กœ ๋Œ๋ ค์ค€๋‹ค.

ํƒ€์ž…์„ ๋ช…์‹œํ•˜๋ฉด IDE ๊ฐ€ ์ž๋™์™„์„ฑ์„ ์ž˜ ํ•ด ์ค๋‹ˆ๋‹ค. ์•ˆ ์ ์–ด๋„ ๋™์ž‘์€ ํ•˜๋Š”๋ฐ ๋ช…์‹œํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts
=== ๋ชจ๋“  ์ฑ… === [ { id: 1, title: '์–ด๋ฆฐ ์™•์ž', author: '์ƒํ…์ฅํŽ˜๋ฆฌ', publishedYear: 1943 }, ... ] ๊ฐœ์ˆ˜: 3

Step 1 ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ์ธ๋ฐ, ์ด์ œ๋Š” ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.


STEP 3. getBookById() ํ•จ์ˆ˜

ID ํ•œ ๊ฐœ๋ฅผ ๋ฐ›์•„ ๊ทธ ์ฑ… ํ•œ ๊ถŒ๋งŒ ๋Œ๋ ค์ค๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฐฐ์—ด์˜ find ๋ฉ”์„œ๋“œ๋ฅผ ์ฒ˜์Œ ์“ฐ๋Š” ์ž๋ฆฌ์˜ˆ์š”.

๐Ÿ“„ lib/books.ts ์— ํ•จ์ˆ˜ ์ถ”๊ฐ€ (์•ž ์ฝ”๋“œ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ , ๋งˆ์ง€๋ง‰์—):

export function getBookById(id: number): Book | undefined { return books.find((b) => b.id === id); }

๐Ÿ“„ scripts/test-books.ts:

import { getAllBooks, getBookById } from "@/lib/books"; console.log("=== ์ „์ฒด ==="); console.log(getAllBooks().length, "๊ถŒ"); console.log("\n=== ID ๋กœ ์ฐพ๊ธฐ ==="); console.log("ID 2:", getBookById(2)); console.log("ID 999 (์—†๋Š” ID):", getBookById(999));

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น books.find((b) => b.id === id)
๋ฐฐ์—ด์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ํ›‘์œผ๋ฉด์„œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ํ•ญ๋ชฉ ์„ ๋Œ๋ ค์ค๋‹ˆ๋‹ค. ์กฐ๊ฑด์€ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ (b) => b.id === id ์ธ๋ฐ, "๊ฐ ์ฑ… b ์— ๋Œ€ํ•ด, ๊ทธ ์ฑ…์˜ id ๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ๋ฐ›์€ id ์™€ ๊ฐ™์œผ๋ฉด ํ†ต๊ณผ" ๋ผ๋Š” ๋œป์ด์—์š”.

๐Ÿ”น Book | undefined
๋ฐ˜ํ™˜ ํƒ€์ž…์— | undefined ๊ฐ€ ๋ถ™์–ด ์žˆ์–ด์š”. find ๋Š” ๋ชป ์ฐพ์œผ๋ฉด undefined ๋ฅผ ๋Œ๋ ค์ฃผ๊ฑฐ๋“ ์š”. ์ด๊ฑธ ๋ช…์‹œํ•ด์•ผ ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์—์„œ "์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ  ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค" ๋Š” ๊ฑธ ์•Œ์•„์ฑ•๋‹ˆ๋‹ค.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts
=== ์ „์ฒด === 3 ๊ถŒ === ID ๋กœ ์ฐพ๊ธฐ === ID 2: { id: 2, title: '๋ฐ๋ฏธ์•ˆ', author: 'ํ—ค๋ฅด๋งŒ ํ—ค์„ธ', publishedYear: 1919 } ID 999 (์—†๋Š” ID): undefined
  • ์žˆ์„ ๋•Œ: ์ฑ… ๊ฐ์ฒด
  • ์—†์„ ๋•Œ: undefined

๋‘ ๊ฒฝ์šฐ๋ฅผ ๋ชจ๋‘ ๋ˆˆ์œผ๋กœ ๋ดค์œผ๋‹ˆ, ๋‚˜์ค‘์— ํŽ˜์ด์ง€์—์„œ "์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค" ๋ถ„๊ธฐ๋ฅผ ๋งŒ๋“ค ๋•Œ ์ž์‹  ์žˆ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.


STEP 4. createBook() ํ•จ์ˆ˜

์ด๋ฒˆ์—” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€๋‹ˆ๋‹ค. ์ƒˆ ์ฑ…์„ ๋“ฑ๋กํ•˜๋ฉด id ๊ฐ€ ์ž๋™์œผ๋กœ ๋งค๊ฒจ์ ธ์•ผ ํ•ด์š”.

๐Ÿ“„ lib/books.ts. ๋‘ ๊ฐ€์ง€๊ฐ€ ๋ฐ”๋€๋‹ˆ๋‹ค:

  1. let nextId = 4; ๋ฅผ books ๋ฐฐ์—ด ์•„๋ž˜์— ์ถ”๊ฐ€
  2. createBook ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€
export type Book = { id: number; title: string; author: string; publishedYear: number; }; const books: Book[] = [ { id: 1, title: "์–ด๋ฆฐ ์™•์ž", author: "์ƒํ…์ฅํŽ˜๋ฆฌ", publishedYear: 1943 }, { id: 2, title: "๋ฐ๋ฏธ์•ˆ", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919 }, { id: 3, title: "1984", author: "์กฐ์ง€ ์˜ค์›ฐ", publishedYear: 1949 }, ]; let nextId = 4; // โฌ…๏ธ ์ถ”๊ฐ€ export function getAllBooks(): Book[] { return books; } export function getBookById(id: number): Book | undefined { return books.find((b) => b.id === id); } // โฌ‡๏ธ ์ถ”๊ฐ€ export function createBook(data: Omit<Book, "id">): Book { const newBook: Book = { id: nextId, ...data }; nextId++; books.push(newBook); return newBook; }

๐Ÿ“„ scripts/test-books.ts:

import { createBook, getAllBooks } from "@/lib/books"; console.log("=== ๋“ฑ๋ก ์ „ ==="); console.log(getAllBooks().length, "๊ถŒ"); const created = createBook({ title: "๋…ธ๋ฅด์›จ์ด์˜ ์ˆฒ", author: "๋ฌด๋ผ์นด๋ฏธ ํ•˜๋ฃจํ‚ค", publishedYear: 1987, }); console.log("\n=== ์ƒˆ๋กœ ๋“ฑ๋กํ•œ ์ฑ… ==="); console.log(created); console.log("\n=== ๋“ฑ๋ก ํ›„ ==="); console.log(getAllBooks().length, "๊ถŒ");

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น Omit<Book, "id">
"Book ํƒ€์ž…์—์„œ id ํ•„๋“œ๋งŒ ๋นผ๋‚ธ ์ƒˆ ํƒ€์ž…" ์ž…๋‹ˆ๋‹ค. ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์€ id ๋ฅผ ๋ชจ๋ฅด๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋งค๊ฒจ ์ค„ ๊ฑฐ๋‹ˆ๊นŒ์š”.

์ด๋ ‡๊ฒŒ ํ˜ธ์ถœ ๊ฐ€๋Šฅ:

createBook({ title: "...", author: "...", publishedYear: 1987 }); // OK

์ด๋ ‡๊ฒŒ๋Š” ์—๋Ÿฌ:

createBook({ id: 99, title: "...", ... }); // โŒ id ๋ฅผ ๋„ฃ์œผ๋ฉด ์•ˆ ๋จ

๐Ÿ”น const newBook: Book = { id: nextId, ...data };

  • id: nextId โ€” ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ๋‹ค์Œ id
  • ...data โ€” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ๊ฐ์ฒด์˜ ํ•„๋“œ๋“ค์„ ํŽผ์ณ์„œ ํ•ฉ์ณ ๋„ฃ๊ธฐ

๊ฒฐ๊ณผ: { id: 4, title: "...", author: "...", publishedYear: 1987 }

๐Ÿ”น nextId++
๋‹ค์Œ ๋“ฑ๋ก์„ ์œ„ํ•ด 1์„ ๋”ํ•ด ๋‘ก๋‹ˆ๋‹ค. let ์ด๋ผ์„œ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿ”น books.push(newBook)
books ๊ฐ€ const ์ธ๋ฐ ์–ด๋–ป๊ฒŒ ์ถ”๊ฐ€๊ฐ€ ๋ ๊นŒ์š”? const ๋Š” ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋‹ค๋ฅธ ๋ฐฐ์—ด๋กœ ๋ชป ๋ฐ”๊พผ๋‹ค๋Š” ๋œป์ผ ๋ฟ, ๋ฐฐ์—ด ๋‚ด์šฉ ์€ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts
=== ๋“ฑ๋ก ์ „ === 3 ๊ถŒ === ์ƒˆ๋กœ ๋“ฑ๋กํ•œ ์ฑ… === { id: 4, title: '๋…ธ๋ฅด์›จ์ด์˜ ์ˆฒ', author: '๋ฌด๋ผ์นด๋ฏธ ํ•˜๋ฃจํ‚ค', publishedYear: 1987 } === ๋“ฑ๋ก ํ›„ === 4 ๊ถŒ
  • id ๊ฐ€ ์ž๋™์œผ๋กœ 4 ๊ฐ€ ๋๊ณ 
  • ์ „์ฒด ๊ฐœ์ˆ˜๊ฐ€ 4๊ถŒ์œผ๋กœ ๋Š˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋งค๋ฒˆ npx tsx ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๊ฒฐ๊ณผ๊ฐ€ ํ•ญ์ƒ ๋˜‘๊ฐ™์ด 4๊ถŒ์œผ๋กœ ๋‚˜์˜ค๋Š” ๊ฒŒ ์ด์ƒํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์–ด์š”. ์ด์œ : ๊ฐ ์‹คํ–‰์€ ์ƒˆ๋กœ์šด Node ํ”„๋กœ์„ธ์Šค ๋ผ ๋งค๋ฒˆ ์ฒ˜์Œ ์ƒํƒœ(3๊ถŒ)์—์„œ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๊ฒŒ ์šฐ๋ฆฌํ•œํ…Œ๋Š” ์ข‹์€ ๊ฑฐ์˜ˆ์š” โ€” ๋งค๋ฒˆ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ.


STEP 5. updateBook() ํ•จ์ˆ˜

์ด๋ฏธ ์žˆ๋Š” ์ฑ…์˜ ๋‚ด์šฉ์„ ํ†ต์งธ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๐Ÿ“„ lib/books.ts ๋งˆ์ง€๋ง‰์— ํ•จ์ˆ˜ ์ถ”๊ฐ€:

export function updateBook( id: number, data: Omit<Book, "id">, ): Book | null { const idx = books.findIndex((b) => b.id === id); if (idx === -1) return null; books[idx] = { id, ...data }; return books[idx]; }

๐Ÿ“„ scripts/test-books.ts:

import { getBookById, updateBook } from "@/lib/books"; console.log("=== ์ˆ˜์ • ์ „ ID 2 ==="); console.log(getBookById(2)); console.log("\n=== updateBook(2, ...) ==="); const updated = updateBook(2, { title: "๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ)", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919, }); console.log("๋ฐ˜ํ™˜๊ฐ’:", updated); console.log("\n=== ์ˆ˜์ • ํ›„ ๋‹ค์‹œ ์กฐํšŒ ==="); console.log(getBookById(2)); console.log("\n=== ์—†๋Š” ์ฑ… ์ˆ˜์ • ์‹œ๋„ ==="); console.log(updateBook(999, { title: "x", author: "y", publishedYear: 0 }));

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น findIndex vs find

  • find ๋Š” ํ•ญ๋ชฉ ์ž์ฒด ๋ฅผ ๋Œ๋ ค์ค๋‹ˆ๋‹ค.
  • findIndex ๋Š” ๊ทธ ํ•ญ๋ชฉ์˜ ์œ„์น˜(์ธ๋ฑ์Šค) ๋ฅผ ๋Œ๋ ค์ค๋‹ˆ๋‹ค. ์—†์œผ๋ฉด -1.

์ˆ˜์ •ํ•˜๋ ค๋ฉด "๋ช‡ ๋ฒˆ์งธ ์ž๋ฆฌ์ธ์ง€" ๋ฅผ ์•Œ์•„์•ผ ํ•˜๋ฏ€๋กœ findIndex ๊ฐ€ ์–ด์šธ๋ ค์š”.

๐Ÿ”น if (idx === -1) return null;
์—†๋Š” ์ฑ…์„ ์ˆ˜์ •ํ•˜๋ผ๋Š” ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด null ์„ ๋Œ๋ ค "๊ทธ๋Ÿฐ ์ฑ… ์—†์–ด์š”" ์‹ ํ˜ธ๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. getBookById ๋Š” undefined ๋ฅผ ์ผ๋Š”๋ฐ, updateBook ์€ null ์ž…๋‹ˆ๋‹ค. ์•ฝ๊ฐ„ ์ผ๊ด€์„ฑ์ด ๋ถ€์กฑํ•ด ๋ณด์ด์ง€๋งŒ ์‹ค๋ฌด์—์„œ ํ”ํžˆ ๋ณด๋Š” ์ฐจ์ด์˜ˆ์š” (์กฐํšŒ โ†’ undefined / ๋ณ€๊ฒฝ โ†’ null ๊ฐ™์€ ๊ด€๋ก€).

๐Ÿ”น books[idx] = { id, ...data };

  • ์˜› ๊ฐ์ฒด๋ฅผ ์ƒˆ ๊ฐ์ฒด๋กœ ํ†ต์งธ๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.
  • { id, ...data } ๋Š” { id: id, ...data } ์˜ ์ถ•์•ฝํ˜•์ž…๋‹ˆ๋‹ค.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts
=== ์ˆ˜์ • ์ „ ID 2 === { id: 2, title: '๋ฐ๋ฏธ์•ˆ', ... } === updateBook(2, ...) === ๋ฐ˜ํ™˜๊ฐ’: { id: 2, title: '๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ)', ... } === ์ˆ˜์ • ํ›„ ๋‹ค์‹œ ์กฐํšŒ === { id: 2, title: '๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ)', ... } === ์—†๋Š” ์ฑ… ์ˆ˜์ • ์‹œ๋„ === null

์„ธ ๊ฐ€์ง€ ๋ชจ๋‘ ํ™•์ธ:

  1. ์ˆ˜์ •์ด ์‹ค์ œ๋กœ ๋ฐ˜์˜๋จ (getBookById ๋กœ ์žฌ์กฐํšŒํ–ˆ๋”๋‹ˆ ์ƒˆ ์ œ๋ชฉ)
  2. ์ˆ˜์ •ํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ๋„ ๋‚˜์˜ด
  3. ์—†๋Š” ์ฑ… ์ˆ˜์ •์€ null

STEP 6. globalThis ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ

์—ฌ๊ธฐ์„œ ๋๋‚ด๋„ ์ฝ”๋“œ๋Š” ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. CLI ํ™˜๊ฒฝ ์—์„œ๋Š” ์ถฉ๋ถ„ํ•ด์š”.

๋ฌธ์ œ๋Š” Next.js dev ๋ชจ๋“œ ์ž…๋‹ˆ๋‹ค. Next.js dev ์„œ๋ฒ„๋Š” ํŒŒ์ผ์„ ์ €์žฅํ•  ๋•Œ๋งˆ๋‹ค ๋ณ€๊ฒฝ๋œ ๋ชจ๋“ˆ์„ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์™€์š”(hot-reload). ์ด๋•Œ lib/books.ts ์•ˆ์˜ books ์™€ nextId ๋ณ€์ˆ˜๊ฐ€ ์ƒˆ ๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™” ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํผ์—์„œ ์ฑ…์„ ๋“ฑ๋กํ–ˆ๋Š”๋ฐ ์ฝ”๋“œ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ €์žฅํ•ด๋„ ๊ทธ ์ฑ…์ด ์‚ฌ๋ผ์ง€๋Š” ๊ฑฐ์˜ˆ์š”.

ํ•ด๊ฒฐ๋ฒ•: ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋“ˆ ์•ˆ์˜ ๋ณ€์ˆ˜ ๊ฐ€ ์•„๋‹ˆ๋ผ ํ”„๋กœ์„ธ์Šค ์ „์—ญ(globalThis) ์— ๋‘๊ธฐ. globalThis ๋Š” hot-reload ๊ฐ€ ์ผ์–ด๋‚˜๋„ ์‚ด์•„๋‚จ์Šต๋‹ˆ๋‹ค.

๐Ÿ“„ lib/books.ts ๋ฅผ ํ†ต์งธ๋กœ ๋‹ค์Œ์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค:

export type Book = { id: number; title: string; author: string; publishedYear: number; }; // Next.js dev ๋ชจ๋“œ์˜ hot-reload ๊ฐ€ ์ผ์–ด๋‚˜๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ด์•„๋‚จ๋„๋ก // ๋ชจ๋“ˆ ์•ˆ์˜ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ "ํ”„๋กœ์„ธ์Šค ์ „์—ญ" ์ธ globalThis ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. type GlobalStore = { __books?: Book[]; __nextId?: number; }; const store = globalThis as unknown as GlobalStore; if (!store.__books) { store.__books = [ { id: 1, title: "์–ด๋ฆฐ ์™•์ž", author: "์ƒํ…์ฅํŽ˜๋ฆฌ", publishedYear: 1943 }, { id: 2, title: "๋ฐ๋ฏธ์•ˆ", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919 }, { id: 3, title: "1984", author: "์กฐ์ง€ ์˜ค์›ฐ", publishedYear: 1949 }, ]; store.__nextId = 4; } export function getAllBooks(): Book[] { return store.__books!; } export function getBookById(id: number): Book | undefined { return store.__books!.find((b) => b.id === id); } export function createBook(data: Omit<Book, "id">): Book { const newBook: Book = { id: store.__nextId!, ...data }; store.__nextId!++; store.__books!.push(newBook); return newBook; } export function updateBook( id: number, data: Omit<Book, "id">, ): Book | null { const idx = store.__books!.findIndex((b) => b.id === id); if (idx === -1) return null; store.__books![idx] = { id, ...data }; return store.__books![idx]; }

๐Ÿ“„ scripts/test-books.ts โ€” ํ•จ์ˆ˜ ์‚ฌ์šฉ์€ ๊ทธ๋Œ€๋กœ์ง€๋งŒ ํ†ตํ•ฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ํ•œ ๋ฒˆ ๋”:

import { createBook, getAllBooks, getBookById, updateBook, } from "@/lib/books"; console.log("=== 1. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ==="); console.log(getAllBooks().length, "๊ถŒ"); console.log("\n=== 2. ID ๋กœ ์กฐํšŒ ==="); console.log("ID 2:", getBookById(2)?.title); console.log("ID 999:", getBookById(999)); console.log("\n=== 3. ์ƒˆ ์ฑ… ๋“ฑ๋ก ==="); const created = createBook({ title: "๋…ธ๋ฅด์›จ์ด์˜ ์ˆฒ", author: "๋ฌด๋ผ์นด๋ฏธ ํ•˜๋ฃจํ‚ค", publishedYear: 1987, }); console.log("์ƒˆ ID:", created.id); console.log("๋“ฑ๋ก ํ›„ ์ „์ฒด:", getAllBooks().length, "๊ถŒ"); console.log("\n=== 4. ์ˆ˜์ • ==="); const updated = updateBook(2, { title: "๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ)", author: "ํ—ค๋ฅด๋งŒ ํ—ค์„ธ", publishedYear: 1919, }); console.log("์ˆ˜์ • ๊ฒฐ๊ณผ:", updated?.title); console.log("์žฌ์กฐํšŒ:", getBookById(2)?.title); console.log("\n=== 5. ์—†๋Š” ์ฑ… ์ˆ˜์ • ==="); console.log(updateBook(999, { title: "x", author: "y", publishedYear: 0 })); console.log("\n=== 6. ์ตœ์ข… ==="); console.log(getAllBooks());

ํ’€์–ด ๋ณด๊ธฐ

๐Ÿ”น type GlobalStore = { __books?: Book[]; __nextId?: number; }
globalThis ์— ์šฐ๋ฆฌ๊ฐ€ ์“ธ ๋‘ ํ•„๋“œ์˜ ๋ชจ์–‘์„ ์ ์–ด ๋‘” ํƒ€์ž…. ? ๋Š” "์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ  ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค" ๋Š” ํ‘œ์‹œ.

๐Ÿ”น const store = globalThis as unknown as GlobalStore;
TypeScript ์—๊ฒŒ "globalThis ๋ฅผ GlobalStore ํƒ€์ž…์ฒ˜๋Ÿผ ๋‹ค๋ฃฐ ๊ฑฐ์•ผ" ๋ผ๊ณ  ์•Œ๋ ค ์ค๋‹ˆ๋‹ค.
as unknown as ๋ผ๋Š” ๋‘ ๋‹จ๊ณ„ ์บ์ŠคํŒ… ์ด ๋“ค์–ด๊ฐ€๋Š” ์ด์œ : globalThis ์˜ ๊ธฐ๋ณธ ํƒ€์ž…๊ณผ GlobalStore ๋Š” ์™„์ „ํžˆ ๋‹ฌ๋ผ์„œ ํ•œ ๋ฒˆ์— ๋ณ€ํ™˜ํ•˜๋ฉด TypeScript ๊ฐ€ "๋„ˆ๋ฌด ์œ„ํ—˜ํ•œ ๋ณ€ํ™˜์ธ๋ฐ?" ๋ผ๋ฉฐ ๊ฑฐ์ ˆํ•ด์š”. unknown ์œผ๋กœ ํ•œ ๋ฒˆ ๊ฑฐ์น˜๋ฉด ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”น if (!store.__books) { ... store.__books = [...]; }
"globalThis ์— __books ๊ฐ€ ์•„์ง ์—†์œผ๋ฉด ์ฒ˜์Œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฑ„์›Œ๋ผ". ์ด๋ฏธ ์žˆ์œผ๋ฉด(=hot-reload ํ›„) ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค. ์ด๊ฒŒ ์‚ด์•„๋‚จ๋Š” ํ•ต์‹ฌ.

๐Ÿ”น store.__books!.find(...)
๋์˜ ! ๋Š” "์ด ๊ฐ’์€ ์ ˆ๋Œ€ undefined ๊ฐ€ ์•„๋‹ˆ์•ผ" ๋ผ๊ณ  TypeScript ํ•œํ…Œ ์•ฝ์†ํ•˜๋Š” ํ‘œ์‹œ. ์œ„์˜ if (!store.__books) ๋กœ ์ฑ„์› ์œผ๋‹ˆ ์ด์ œ๋ถ€ํ„ฐ๋Š” ๋ถ„๋ช…ํžˆ ์žˆ๋‹ค โ€” ๊ทธ๊ฑธ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋ชจ๋ฅด๋‹ˆ๊นŒ ์šฐ๋ฆฌ๊ฐ€ ์•Œ๋ ค ์ฃผ๋Š” ๊ฑฐ์˜ˆ์š”.

โœ… ํ™•์ธํ•˜๊ธฐ

npx tsx scripts/test-books.ts
=== 1. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ === 3 ๊ถŒ === 2. ID ๋กœ ์กฐํšŒ === ID 2: ๋ฐ๋ฏธ์•ˆ ID 999: undefined === 3. ์ƒˆ ์ฑ… ๋“ฑ๋ก === ์ƒˆ ID: 4 ๋“ฑ๋ก ํ›„ ์ „์ฒด: 4 ๊ถŒ === 4. ์ˆ˜์ • === ์ˆ˜์ • ๊ฒฐ๊ณผ: ๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ) ์žฌ์กฐํšŒ: ๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ) === 5. ์—†๋Š” ์ฑ… ์ˆ˜์ • === null === 6. ์ตœ์ข… === [ { id: 1, title: '์–ด๋ฆฐ ์™•์ž', ... }, { id: 2, title: '๋ฐ๋ฏธ์•ˆ (๊ฐœ์ •ํŒ)', ... }, { id: 3, title: '1984', ... }, { id: 4, title: '๋…ธ๋ฅด์›จ์ด์˜ ์ˆฒ', ... } ]

Step 5 ์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ ๊ฐ€ ๋‚˜์˜ค๋ฉด ์„ฑ๊ณต์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋งŒ ๋ฐ”๋€Œ์—ˆ์ง€ ๋™์ž‘์€ ๊ทธ๋Œ€๋กœ๋‹ˆ๊นŒ์š”.

CLI ํ™˜๊ฒฝ์—์„œ๋Š” globalThis ์˜ ์ด์ ์ด ์•ˆ ๋ณด์ž…๋‹ˆ๋‹ค(๋งค ์‹คํ–‰์ด ์ƒˆ ํ”„๋กœ์„ธ์Šค). ํ•˜์ง€๋งŒ Next.js dev ์„œ๋ฒ„๋ฅผ ๋„์šฐ๊ณ  app/books/new ์—์„œ ์ฑ…์„ ๋“ฑ๋กํ•œ ๋’ค lib/books.ts ์˜ ์ฃผ์„ ํ•œ ์ค„์„ ๋ฐ”๊ฟ” ์ €์žฅํ•ด ๋ณด์„ธ์š”. ์ƒˆ๋กœ ๋“ฑ๋กํ•œ ์ฑ…์ด ์‚ฌ๋ผ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๋ณธ ํŠœํ† ๋ฆฌ์–ผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

์ด์ œ lib/books.ts ๊ฐ€ ๋ณธ ํŠœํ† ๋ฆฌ์–ผ(TUTORIAL.md)์˜ STEP 2 ๊ฒฐ๊ณผ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. Next.js ํŽ˜์ด์ง€/๋ผ์šฐํŠธ๋ฅผ ํ†ตํ•ด์„œ๋„ ๊ฐ™์€ ํ•จ์ˆ˜๋“ค์„ ๋ถ€๋ฅด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

dev ์„œ๋ฒ„์—์„œ๋„ ํ™•์ธ

npm run dev

http://localhost:3300/api/books ๋ฅผ ์—ด๋ฉด ๊ฐ™์€ ์ฑ… 3๊ถŒ์ด JSON ์œผ๋กœ ๋‚˜์˜ต๋‹ˆ๋‹ค. CLI ์—์„œ ํ™•์ธํ•œ ํ•จ์ˆ˜๊ฐ€ ๊ทธ๋Œ€๋กœ API ๋ผ์šฐํŠธ์—์„œ ํ˜ธ์ถœ๋˜๊ณ  ์žˆ์–ด์š”.

scripts ํด๋” ์ฒ˜๋ฆฌ

scripts/test-books.ts ๋Š” ํ•™์Šต์šฉ ์‚ฐ์ถœ๋ฌผ์ด๋ผ ๊ทธ๋Œ€๋กœ ๋‘ฌ๋„ ๋ณธ ํ”„๋กœ์ ํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ(npm run build) ์—์„œ๋„ ๋ฌด์‹œ๋˜๊ณ , dev ์„œ๋ฒ„์—์„œ๋„ ์•ˆ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค. ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  ์‹ถ์œผ๋ฉด scripts/ ํด๋” ์ „์ฒด๋ฅผ ์ง€์šฐ์„ธ์š”.

rm -rf scripts

tsx ๋„ ๋” ์ด์ƒ ์•ˆ ์“ฐ๊ฒ ๋‹ค๋ฉด ์˜์กด์„ฑ์—์„œ ์ œ๊ฑฐ:

npm uninstall tsx

์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๊ฒƒ

๋‹จ๊ณ„์ƒˆ๋กœ ๋ฐฐ์šด ๊ฒƒ
Step 1export, type, Book[] ๊ฐ™์€ ๊ธฐ์ดˆ ํƒ€์ž…
Step 2ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ export ํ•˜๋Š” ํŒจํ„ด
Step 3Array#find, `T
Step 4Omit<T, K>, ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž, const ๋ฐฐ์—ด์˜ push
Step 5Array#findIndex, null ๋กœ "์—†์Œ" ํ‘œํ˜„
Step 6globalThis ์บ์ŠคํŒ…, ! non-null assertion

๋‹ค์Œ์— ํ•ด ๋ณผ ๋งŒํ•œ ๊ฒƒ

  • deleteBook(id) ์ถ”๊ฐ€ โ€” splice ๋˜๋Š” filter ๋กœ ํ•œ ์ค„ ์ •๋„.
  • ๊ฒ€์ƒ‰ ํ•จ์ˆ˜ searchBooks(keyword) โ€” title.includes(keyword) ํ™œ์šฉ.
  • ์ •๋ ฌ sortBooksByYear() โ€” [...books].sort(...) ๋กœ ์›๋ณธ์„ ์•ˆ ๊ฑด๋“œ๋ฆฌ๊ณ  ์ •๋ ฌ.

CLI ์—์„œ ๋งค๋ฒˆ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” ์ด ํŒจํ„ด์€ ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋“  ๋˜‘๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ์–ด์š”. ์ž‘๊ฒŒ ๋งŒ๋“ค๊ณ , ์‹คํ–‰ํ•ด์„œ ๋ณด๊ณ , ๊ทธ๋‹ค์Œ ํ•œ ์ค„์„ ๋”ํ•œ๋‹ค โ€” ์ด๊ฒŒ ์ง€์น˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ๋Š˜๋ฆฌ๋Š” ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋Œ“๊ธ€

๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...

๋Œ“๊ธ€์„ ์ž‘์„ฑํ•˜๋ ค๋ฉด ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.