TypeScript Course ๐ฅ
ReactJS์ NestJS๋ฅผ ๋ฉ์ธ์ผ๋ก ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ก์, ํ์ ์คํฌ๋ฆฝํธ์ ๋ํ ๋ช ํํ ์ดํด๋ ํ์์ ์ด๊ฒ ์ฃ . freeCodeCamp์ ํ์ ์คํฌ๋ฆฝํธ ๊ฐ์ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก, TS์ ๊ธฐ์ด์ ๋ํด ์ ๋ฆฌํ๊ฒ ์ต๋๋ค. ์ค๋์ Bob Ziroll(๋ฐฅ ์ง๋กค) ์ ์๋์ ๋ชจ์ จ์ต๋๋ค. ๋ฐ์
0. Overview ๐
ReactJS์ NestJS๋ฅผ ๋ฉ์ธ์ผ๋ก ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ก์, ํ์ ์คํฌ๋ฆฝํธ์ ๋ํ ๋ช ํํ ์ดํด๋ ํ์์ ์ด๊ฒ ์ฃ . freeCodeCamp์ ํ์ ์คํฌ๋ฆฝํธ ๊ฐ์ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก, TS์ ๊ธฐ์ด์ ๋ํด ์ ๋ฆฌํ๊ฒ ์ต๋๋ค.
์ค๋์ Bob Ziroll(๋ฐฅ ์ง๋กค) ์ ์๋์ ๋ชจ์ จ์ต๋๋ค. ~~๋ฐ์์ฃผ์~~
reference: https://www.youtube.com/watch?v=SpwzRDUQ1GI&t=330s
1. Introduction ๐
ํ์ ์คํฌ๋ฆฝํธ(์ดํ TS)๋ ์๋ฐ์คํฌ๋ฆฝํธ(์ดํ JS)์ Superset์ ๋๋ค. ์ฆ, JS์ ํ์ ์ง์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๊ฐ TS๋ผ๊ณ ํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ชจ๋ ์ ํจํ JS ์ฝ๋๋ TS์์๋ ์ ํจํฉ๋๋ค.
Bob Ziroll ์ ์๋๊ป์๋, TS๊ฐ ๊ฐ๋ฐ์์ ์์ ๊ฐ๊ณผ ์์ฐ์ฑ์ ์ ๊ณ ํจ๊ณผ ๋์์ ๋ฐ์ ๊ฐ๋ฅํ ๋ฌธ์ ๋ฅผ ์๋ฐฉํ ์ ์์ด์, TS๋ฅผ ๋ฐฐ์์ผ ํ๋ค๊ณ ๋ง์ํ์ญ๋๋ค. ์ ๋ ์ ์ ์ผ๋ก ๋์ํฉ๋๋ค.
๋์ฑ์ด, ์ ์ ๊ฒฝ์ฐ ๋ฐฑ์๋๋ฅผ NestJS๋ผ๋ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐํ๊ณ ์๋๋ฐ์, NestJS๋ TS๋ก ์์ฑ๋ ํ๋ ์์ํฌ์ ๋๋ค. ๋น ์ ธ๋๊ฐ ๊ตฌ๋ฉ์ด ์๋ ๊ฒ์ด์ง์. ํผํ ์ ์์ผ๋ฉด ์ฆ๊ฒจ์ผ์ง์.
Bob Ziroll ์ ์๋์ ์น๊ตฌ๋ถ๊ป์ ์ด๋ฐ ๋ง์์ ํ์ จ๋ต๋๋ค.
TS is not making your life terrible. It's just showing you how terrible your life already is.
์ธ์ ํ๊ธฐ ์ซ์ต๋๋ค.(์ ํํ ํฉํธ๋ผ๋ ๋ป)
๊ฐ๋จํ Pizza App์ ๋ง๋ค๋ฉฐ, TS ๊ด๋ จ ์ด๋ก ์ ์ ๋ฆฌํ๊ณ ์ ํฉ๋๋ค.
2. Pizza App Fundamentals ๐
2-1. Intro to Pizza App ๐ข
// ์ด๊ธฐ ํผ์ ๋ฉ๋ด ๋ฐฐ์ด. ๊ฐ ํผ์๋ ์ด๋ฆ(name)๊ณผ ๊ฐ๊ฒฉ(price)์ ๊ฐ์ง.
const menu = [
{ name: "Margherita", price: 8 },
{ name: "Pepperoni", price: 10 },
{ name: "Hawaiian", price: 10 },
{ name: "Veggie", price: 9 },
];// ํผ์ ํ๋งค ์์ต์ ์ ์ฅํ๋ ๋ณ์.
// const๋ก ์ ์ธ๋์ด ๊ฐ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ์ง๋ง, ์๋์์ ๋ณ๊ฒฝ์ ์๋ํจ (์๋๋ ์ค๋ฅ).
const cashInRegister = 100;
// ์ฃผ๋ฌธ์ ๋ถ์ฌํ ๊ณ ์ ID๋ฅผ ์ํ ๋ณ์.
// const๋ก ์ ์ธ๋์ด ์๋์์ ++ ์ฐ์ฐ ์ ์ค๋ฅ ๋ฐ์ (์๋๋ ์ค๋ฅ).
const nextOrderId = 1;
// ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ ์ฃผ๋ฌธ ๋ชฉ๋ก์ ์ ์ฅํ ํ ๋ฐฐ์ด.
const orderQueue = [];// ์๋ก์ด ํผ์ ๋ฉ๋ด ํญ๋ชฉ์ ์ถ๊ฐํ๋ ํจ์.
// pizzaObj๋ { name: string, price: number } ํ์์ด์ด์ผ ํจ.
// ์ ๋ฌ๋ ํผ์ ๊ฐ์ฒด๋ฅผ ๋ฉ๋ด์ ์ถ๊ฐ
function addNewPizza(pizzaObj) {
menu.push(pizzaObj);
}// ํผ์ ์ฃผ๋ฌธ์ ์์ฑํ๊ณ ์ฃผ๋ฌธ ํ์ ์ถ๊ฐํ๋ ํจ์.
// ์ฃผ๋ฌธ ์ ์ ํํ ํผ์์ ๊ฐ๊ฒฉ์ cashInRegister์ ์ถ๊ฐํ๊ณ , ์ฃผ๋ฌธ ๊ฐ์ฒด๋ฅผ ์์ฑํจ.
// ์ฌ์ฉ์๊ฐ ์ฃผ๋ฌธํ ํผ์์ ์ด๋ฆ๊ณผ ์ผ์นํ๋ ํญ๋ชฉ์ ๋ฉ๋ด์์ ์ฐพ์
// ์ ํ๋ ํผ์์ ๊ฐ๊ฒฉ์ ์์ต์ ๋ํจ.
// ํ์ง๋ง cashInRegister๋ const๋ผ์ ์ด ์ค์์ ๋ฐํ์ ์๋ฌ ๋ฐ์ ์์ .
// ์๋ก์ด ์ฃผ๋ฌธ ๊ฐ์ฒด๋ฅผ ์์ฑ. ๊ณ ์ ID, ํผ์ ์ ๋ณด, ์ํ ํฌํจ.
// nextOrderId๋ const๋ก ์ ์ธ๋์ด ์์ด์ ++ ์ฐ์ฐ ์ ์๋ฌ ๋ฐ์ ์์ .
// ์์ฑ๋ ์ฃผ๋ฌธ์ ์ฃผ๋ฌธ ํ์ ์ถ๊ฐ
// ์์ฑ๋ ์ฃผ๋ฌธ์ ๋ฐํ
function placeOrder(pizzaName) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
cashInRegister += selectedPizza.price;
const newOrder = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}// ํน์ ์ฃผ๋ฌธ์ ์๋ฃ ์ํ๋ก ๋ณ๊ฒฝํ๋ ํจ์
// ์ ๋ฌ๋ ID์ ์ผ์นํ๋ ์ฃผ๋ฌธ์ ์ฃผ๋ฌธ ํ์์ ์ฐพ์
// ์ฐพ์ ์ฃผ๋ฌธ์ ์ํ๋ฅผ "complete"์ผ๋ก ๋ณ๊ฒฝ
// ์
๋ฐ์ดํธ๋ ์ฃผ๋ฌธ ๊ฐ์ฒด๋ฅผ ๋ฐํ
function completeOrder(orderId) {
const order = orderQueue.find((order) => order.id === orderId);
order.status = "complete";
return order;
}// ์๋ก์ด ํผ์ ํญ๋ชฉ๋ค์ ๋ฉ๋ด์ ์ถ๊ฐํจ
// ํ์ง๋ง price๊ฐ ์๋ cost๋ผ๋ ์๋ชป๋ ํค๋ฅผ ์ฌ์ฉ โ ์ดํ ๊ฐ๊ฒฉ ๊ณ์ฐ ์ ๋ฌธ์ ๋ฐ์
addNewPizza({ name: "Chicken Bacon Ranch", cost: 12 });
addNewPizza({ name: "BBQ Chicken", cost: 12 });
addNewPizza({ name: "Spicy Sausage", cost: 11 });
// "Chicken Bacon Ranch" ํผ์๋ฅผ ์ฃผ๋ฌธํจ
// ์์์ price๊ฐ ์๋๋ผ cost๋ก ์ถ๊ฐํ๊ธฐ ๋๋ฌธ์ selectedPizaa.price๋ undefined๊ฐ ๋๊ณ ,
// cashInRegister += undefined โ NaN ๋ฐ์
placeOrder("Chicken Bacon Ranch");
// ๋ฌธ์์ด "1"์ ID๋ก ์ ๋ฌ โ ์ค์ ์ฃผ๋ฌธ ID๋ ์ซ์ 1์ด๋ฏ๋ก ๋น๊ต ์ false๊ฐ ๋์ด
// order๋ undefined๊ฐ ๋๊ณ , ์ดํ order.status ์ ๊ทผ ์ ๋ฐํ์ ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ
completeOrder("1");
// ์ต์ข
๊ฒฐ๊ณผ ์ถ๋ ฅ
console.log("Menu: ", menu);
console.log("Cash in register: ", cashInRegister);
console.log("Order Queue: ", orderQueue);ํผ์ ์ฃผ๋ฌธ ๋ก์ง์ ์์ฑํ์ต๋๋ค. ๊ฒฐํจ์ด ๋ง์ JS ์ฝ๋์ด๊ณ , ์ ์ฌ์ ์ธ ๊ฒฐํจ์ ์ฃผ์์ผ๋ก ํ๊ธฐํด๋์ ์ํฉ์ ๋๋ค.
ํ์ฌ์ .js ํ์ผ์์ .ts ํ์ผ๋ก ๋์ผํ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด, ์์ฒญ๋ ์๋ฌ ๋ผ์ธ์ ํ์ธํ ์ ์๊ฒ ๋ฉ๋๋ค.
2-2. Move code to TS ๐ข
index.ts ํ์ผ์ ์์ฑํ๊ณ , ๊ธฐ์กด์ index.js์ ์์ฑํ๋ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ฎ๊ฒผ์ต๋๋ค.
๊ฐ๋จํ๊ฒ TypeError: Assignment to constant variable. ๋ถ๋ถ๋ง ์์ ํด ๋ณด๊ฒ ์ต๋๋ค.
// ํผ์ ํ๋งค ์์ต์ ์ ์ฅํ๋ ๋ณ์.
// const๋ก ์ ์ธ๋์ด ๊ฐ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ์ง๋ง, ์๋์์ ๋ณ๊ฒฝ์ ์๋ํจ (์๋๋ ์ค๋ฅ).
// let์ผ๋ก ์์
let cashInRegister = 100;
// ์ฃผ๋ฌธ์ ๋ถ์ฌํ ๊ณ ์ ID๋ฅผ ์ํ ๋ณ์.
// const๋ก ์ ์ธ๋์ด ์๋์์ ++ ์ฐ์ฐ ์ ์ค๋ฅ ๋ฐ์ (์๋๋ ์ค๋ฅ).
// let์ผ๋ก ์์
let nextOrderId = 1;
// ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ ์ฃผ๋ฌธ ๋ชฉ๋ก์ ์ ์ฅํ ํ ๋ฐฐ์ด.
const orderQueue = [];const๋ฅผ let์ผ๋ก ๋ณ๊ฒฝํ ๊ฒ์ด ์ค์ํ ๊ฒ์ด ์๋๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ํ์ ์คํฌ๋ฆฝํธ๋ก ์ ํํ์ ๋ ํ์ ์คํฌ๋ฆฝํธ๊ฐ ์ ์ฌ์ ์ค๋ฅ๋ฅผ ์ฆ์ ๊ฐ์งํ๊ณ ๋ณด์ฌ์ค๋ค๋ ์ , ๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํตํด ์ฝ๋์ ๋ฌธ์ ์ ์ ์กฐ๊ธฐ์ ์๋ณํ๊ณ ์์ ํ ์ ์๋ค๋ ์ ์ด ์ค์ํ๊ฒ ์ต๋๋ค.
2-3. Defensive coding ๐ข
์ฝ๋๋ฅผ ์์ฑํ๋ฉฐ, ๋ค์ํ ์๋๋ฆฌ์ค๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง์ ๋ํ ์ ๊ทผ ๋ฐฉ์์๋ ๋ ๊ฐ์ง๊ฐ ์์ต๋๋ค.
Happy Path๋, ๋ชจ๋ ๊ฒ์ด ์๋ฒฝํ๊ฒ ์ ์๋ํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๊ณ ์์ฑํ๋ ์ฝ๋์ ๋๋ค. ๋ฌธ์ ๋ฐ์ ๊ฐ๋ฅ์ฑ์ด๋ ์์ธ ์ํฉ์ ๊ณ ๋ คํ์ง ์๊ณ , ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋๋ ๊ฐ์ฅ ์ด์์ ์ธ ํ๋ฆ์ ์ด์ ์ ๋ง์ถฐ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ฉด Sad Path๋, ์ฝ๋๋ฅผ ์์ฑํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์์ ์ธ์งํ๊ณ , ์์ธ ์ํฉ์ด๋ ์์ง ์ผ์ด์ค๋ฅผ ์์ํ์ฌ ์ฒ๋ฆฌํ๋ ์ฝ๋์ ๋๋ค. ๋ฐ์ ๊ฐ๋ฅํ ๋ฌธ์ ์ํฉ์ ๊ณ ๋ คํ๊ณ , ๊ฐ ๋ฌธ์ ์ ๋ํ ๋ฐฉ์ด์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋์ฃ .
TS๋ ๊ฐ๋ฐ์๊ฐ Sad Path๋ฅผ ๊ณ ๋ คํ๋๋ก ๊ฐ์ ํ๋ ์ญํ ์ ํฉ๋๋ค. ์ด์ ์ ์์ฑํ JS ์ฝ๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
function placeOrder(pizzaName) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
cashInRegister += selectedPizza.price;
const newOrder = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}selectedPizza๋, ๋ฉ๋ด์์ ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ํน์ ํผ์์ ๋๋ค.
๋ง์ฝ ๊ณ ๊ฐ์ด ๋ฉ๋ด์ ์๋ ํผ์๋ฅผ ์ฃผ๋ฌธํ๋ค๋ฉด selectedPizza๋ undefined๊ฐ ๋ฉ๋๋ค. ํ์ ์ฝ๋์์ selectedPizza์ price์ ์ ๊ทผํ๊ณ ์๋๋ฐ, selectedPizza๊ฐ undefined๋ผ๋ฉด ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ ๋๋ค.
selectedPizza๊ฐ undefined ์ธ์ง ํ์ธํ๋ ๋ฐฉ์ด์ ์ธ ์กฐ๊ฑด๋ฌธ์ ์์ฑํ๋ ๊ฒ์ด ์ข๊ฒ ์ต๋๋ค.
function placeOrder(pizzaName) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
if (!selectedPizza) {
console.error(`${pizzaName} does not exist in the menu.`);
return;
}
cashInRegister += selectedPizza.price;
const newOrder = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}๐จ ์ค๊ฐ ์์ฝ
ํผ์ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ JS์์ TS๋ก์ ์ ํ ๊ณผ์ ๊ณผ ๋ฐฉ์ด์ ์ฝ๋ฉ์ ์ค์์ฑ์ ๊ดํด ์ค๋ช ํ์ต๋๋ค. JS์์ ๋ฐ์ํ๋ ์ฌ๋ฌ ์ ์ฌ์ ์ค๋ฅ๋ค(์์ ์ฌํ ๋น, undefined ์ฐธ์กฐ ๋ฑ)์ด TS๋ฅผ ํตํด ์ปดํ์ผ ์์ ์ ๊ฐ์ง๋ ์ ์์ผ๋ฉฐ, 'Happy Path'๊ฐ ์๋ 'Sad Path'๋ฅผ ๊ณ ๋ คํ ๋ฐฉ์ด์ ์ฝ๋ฉ ๋ฐฉ์์ ํตํด ๋ฉ๋ด์ ์๋ ํผ์ ์ฃผ๋ฌธ๊ณผ ๊ฐ์ ์์ธ ์ํฉ์ ์ฒ๋ฆฌํ๋ ์ค์์ฑ์ ๊ฐ์กฐํ์ต๋๋ค.
3. TypeScript Basics ๐
3-1. Obligatory types basics lesson ๐ข
Obligatory types๋, ๋ง ๊ทธ๋๋ก TS์์ ํ์์ ์ผ๋ก ์์์ผ ํ๋ ๊ธฐ๋ณธ ํ์ ๊ฐ๋ ์ ์๋ฏธํฉ๋๋ค.
let myName: string = "minkwan";
let numberOfWheels: number = 4;
let isStudent: boolean = false;๋ณ์์ ๊ธฐ๋ณธ ํ์ ์ ์ค์ ํ๋ ์ฝ๋์ ๋๋ค. ์ ๋ฐฉ์์ด Pizza App์์ ์ด๋ป๊ฒ ์ ์ฉ๋๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
3-2. Add type to orderId ๐ข
function completeOrder(orderId: number) {
const order = orderQueue.find((order) => order.id === orderId);
order.status = "complete";
return order;
}completeOrder ํจ์๊ฐ ๋ฐ๋ orderId ๋ณ์์ ๊ธฐ๋ณธ ํ์ ์ number๋ก ์ง์ ํ์ต๋๋ค. ๋ฐ๋ผ์ ์ฌ์ฉ์ฒ์์๋ number๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค.
completeOrder(1);๋ฌธ์์ด์ด ์๋๋ผ number๋ฅผ ์ ์ฉํ๊ฒ ๋ฉ๋๋ค.
3-3. Defining Custom Types ๐ข
๋ณ์๊ฐ ๊ฐ์ ธ์ผ ํ ์์ฑ๊ณผ ๊ฐ ์์ฑ์ ํ์ ์ ์ปค์คํ ํ ์ ์์ต๋๋ค.
type Person = {
name: string;
age: number;
isStudent: boolean;
};
let person1: Person = {
name: "Joe",
age: 42,
isStudent: true,
};
let person2: Person = {
name: "minkwan",
age: 28,
isStudent: false,
};person1๊ณผ person2๋, Person ์ปค์คํ ํ์ ์ ๋ช ์๋ ๋ด์ฉ์ ๋ฐ๋ฅด๊ฒ ๋ฉ๋๋ค.
๐จ ์ค๊ฐ ์์ฝ
TS์์ ํ์์ ์ผ๋ก ์์์ผ ํ ๊ธฐ๋ณธ ํ์ (string, number, boolean ๋ฑ)์ ๋ณ์์ ์ง์ ํ๋ ๋ฐฉ์์ ํ์ธํ์ต๋๋ค. ํจ์ ๋งค๊ฐ๋ณ์์ ํ์ ์ ๋ช ์ํ์ฌ(์: orderId๋ฅผ number๋ก ์ง์ ) ํธ์ถ ์ ์ ์ ํ ํ์ ๋ง ํ์ฉํ๋๋ก ์ค์ ํ์ต๋๋ค. ์ถ๊ฐ์ ์ผ๋ก, ๊ฐ๋ฐ์๊ฐ ์ง์ ํ์ํ ์์ฑ๊ณผ ๊ทธ ํ์ ์ ์ ์ํ ์ปค์คํ ํ์ (์: Person ํ์ )์ ๋ง๋ค์ด ์ฌ๋ฌ ๋ณ์๊ฐ ๋์ผํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ก ํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ดค์ต๋๋ค.
4. Working with Types ๐
4-1. Adding a Pizza type ๐ข
์์์ ํ์ตํ ๋๋ก Pizza๋ผ๋ ์ปค์คํ ํ์ ์ ์์ฑํ์ต๋๋ค.
type Pizza = {
name: string;
price: number;
};๋ฉ๋ด์ ์๋ก์ด ํผ์๋ฅผ ์ถ๊ฐํ ๋, ์์์ ์ ์ํ ์ปค์คํ ํ์ ์ ๋ฐ๋ฅด๋๋ก ์ค์ ํ์ต๋๋ค.
function addNewPizza(pizzaObj: Pizza) {
menu.push(pizzaObj);
}์ด์ ์ฝ๋์์ addNewPizza() ํจ์์ price๊ฐ ์๋ cost๋ฅผ ์ ๋ฌํ๋ ๋ชจ์ต์ ํ์ธํ ์ ์์ต๋๋ค. ์ปค์คํ ํ์ ์ ๋ง๊ฒ cost๋ฅผ price๋ก ๋ณ๊ฒฝํฉ๋๋ค.
addNewPizza({ name: "Chicken Bacon Ranch", cost: 12 });
addNewPizza({ name: "BBQ Chicken", cost: 12 });
addNewPizza({ name: "Spicy Sausage", cost: 11 });addNewPizza({ name: "Chicken Bacon Ranch", price: 12 });
addNewPizza({ name: "BBQ Chicken", price: 12 });
addNewPizza({ name: "Spicy Sausage", price: 11 });pizzaName์ ํ์ ๋ string์ผ๋ก ์ง์ ํฉ์๋ค.
function placeOrder(pizzaName: string) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
if (!selectedPizza) {
console.error(`${pizzaName} does not exist in the menu.`);
return;
}
cashInRegister += selectedPizza.price;
const newOrder = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}
...
placeOrder("Chicken Bacon Ranch");
...4-2. Nested object types ๐ข
TS์์ ์ค์ฒฉ ๊ฐ์ฒด ํ์ (Nested Object Types)์ ์ ์ํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐํ๊ณ ์ ํฉ๋๋ค.
address๋ฅผ Person ํ์ ์์์ ์ง์ ๊ฐ์ฒด ๊ตฌ์กฐ๋ก ์ ์ํ ์ ์์ต๋๋ค. address ๊ตฌ์กฐ๊ฐ ๋ฐ๋ณต๋๋ฉด ์ค๋ณต์ด ์๊ธฐ๊ณ , ์ฌ์ฌ์ฉ์ฑ์ด ๋จ์ด์ง ์ ์๊ฒ ์ต๋๋ค.
type Person = {
name: string;
age: number;
isStudent: boolean;
address: {
street: string;
city: string;
country: string;
};
};
let person1: Person = {
name: "Joe",
age: 42,
isStudent: true,
address: {
street: "123 Main",
city: "Anytown",
country: "USA",
},
};
let person2: Person = {
name: "minkwan",
age: 28,
isStudent: false,
address: {
street: "123 Main",
city: "Anytown",
country: "USA",
},
};์ด๋ฒ์ address์ ํ์ ์ ๋ฐ๋ก Address ํ์ ์ผ๋ก ๋ถ๋ฆฌํ์ต๋๋ค. Person ํ์ ์ ์ด์ address: Address๋ผ๊ณ ๋ช ์ํด์ Address ํ์ ์ ์ฌ์ฉํ ์ ์๊ฒ ๋์์ต๋๋ค. ๋ค๋ฅธ ํ์ ์์๋ Address ํ์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
type Address = {
street: string;
city: string;
country: string;
};
type Person = {
name: string;
age: number;
isStudent: boolean;
address: Address;
};
let person1: Person = {
name: "Joe",
age: 42,
isStudent: true,
address: {
street: "123 Main",
city: "Anytown",
country: "USA",
},
};
let person2: Person = {
name: "minkwan",
age: 28,
isStudent: false,
address: {
street: "123 Main",
city: "Anytown",
country: "USA",
},
};4-3. Optional properties ๐ข
์์ฑ ์ด๋ฆ ๋ค์ ?๋ฅผ ๋ถ์ด๋ฉด, ํด๋น ์์ฑ์ optional ํ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. person1์์ address๋ฅผ ์ฌ์ฉํ์ง ์์๋ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๊ฒ ๋ฉ๋๋ค.
type Address = {
street: string;
city: string;
country: string;
};
type Person = {
name: string;
age: number;
isStudent: boolean;
address?: Address;
};
let person1: Person = {
name: "Joe",
age: 42,
isStudent: true,
};
let person2: Person = {
name: "minkwan",
age: 28,
isStudent: false,
address: {
street: "123 Main",
city: "Anytown",
country: "USA",
},
};๊ทธ๋ฐ๋ฐ ์์ฑ์ optional ํ๊ฒ ์ง์ ํ ๋์๋ ์ฃผ์ํด์ผ ํ ์ ์ด ์์ต๋๋ค.
function displayInfo(person) {
console.log(person.name);
console.log(person.address?.street);
}
displayInfo(person1);์ ์ฝ๋๋ฅผ ์คํํ๋ฉด person1์๋ address ์์ฑ์ด ์๊ธฐ ๋๋ฌธ์, ๋จ์ํ person.address.street๋ก ์ ๊ทผํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค. optional ํ๊ฒ ์ง์ ํ ๋งํผ, ํ์
์์ ์ฑ์ด ๊ฐ์๋ ๊ฒ์ด์ง์. ๊ทธ๋์ ์ ์ฝ๋์ฒ๋ผ person.address?.street๋ก ์ต์
๋ ์ฒด์ด๋์ ์ ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
4-4. Adding an Order type ๐ข
Order type์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
type Order = {
id: number;
pizza: Pizza;
status: string;
};Order type์ orderQueue์ ์ ์ฉํฉ๋๋ค.
const orderQueue: Order = [];Order๋ ๊ฐ์ฒด ํ์ ์ธ๋ฐ orderQueue๋ ๋ฐฐ์ด์ด๋ผ๋ ๋ฌธ์ ์ ์ด ์์ต๋๋ค.
4-5. Typing arrays ๐ข
type Person = {
name: string;
age: number;
isStudent: boolean;
};
let person1: Person = {
name: "Joe",
age: 42,
isStudent: true,
};
let person2: Person = {
name: "minkwan",
age: 28,
isStudent: false,
};
let people: Person[] = [person1, person2];ํต์ฌ์ let people: Person[] = [person1, person2];์
๋๋ค.
people์ด Person ๊ฐ์ฒด๋ค๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด ํ์ ์์ ๋ช ์ํ๋ ์ฝ๋์ ๋๋ค. ์ด ๋ด์ฉ์ Pizza App์ ์ ์ฉํด ๋ณด๊ฒ ์ต๋๋ค.
4-6. Type orderQueue ๐ข
orderQueue๊ฐ Order๋ก ๊ตฌ์ฑ๋ '๋ฐฐ์ด ํ์ '์์ ๋ช ์ํฉ๋๋ค.
const orderQueue: Order[] = [];function completeOrder(orderId: number) {
const order = orderQueue.find((order) => order.id === orderId);
order.status = "complete";
return order;
}order ๊ฐ์ด ์์ ์๋ ์๊ฒ ์ฃ . ์ด์ ๋ํ ๋ฐฉ์ด์ ์ธ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
function completeOrder(orderId: number) {
const order = orderQueue.find((order) => order.id === orderId);
if (!order) {
console.error(`${orderId} was not found.`);
return;
}
order.status = "complete";
return order;
}๋ชจ๋ ์ค๋ฅ๊ฐ ์์ ๋ TS ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
type Pizza = {
name: string;
price: number;
};
type Order = {
id: number;
pizza: Pizza;
status: string;
};
const menu = [
{ name: "Margherita", price: 8 },
{ name: "Pepperoni", price: 10 },
{ name: "Hawaiian", price: 10 },
{ name: "Veggie", price: 9 },
];
let cashInRegister = 100;
let nextOrderId = 1;
const orderQueue: Order[] = [];
function addNewPizza(pizzaObj: Pizza) {
menu.push(pizzaObj);
}
function placeOrder(pizzaName: string) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
if (!selectedPizza) {
console.error(`${pizzaName} does not exist in the menu.`);
return;
}
cashInRegister += selectedPizza.price;
const newOrder = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}
function completeOrder(orderId: number) {
const order = orderQueue.find((order) => order.id === orderId);
if (!order) {
console.error(`${orderId} was not found.`);
return;
}
order.status = "complete";
return order;
}
addNewPizza({ name: "Chicken Bacon Ranch", price: 12 });
addNewPizza({ name: "BBQ Chicken", price: 12 });
addNewPizza({ name: "Spicy Sausage", price: 11 });
placeOrder("Chicken Bacon Ranch");
completeOrder(1);
console.log("Menu: ", menu);
console.log("Cash in register: ", cashInRegister);
console.log("Order Queue: ", orderQueue);๐จ ์ค๊ฐ ์์ฝ
TS์์ ํ์ ์์คํ ์ ํ์ฉํ์ฌ ํผ์ ์ฃผ๋ฌธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฝ๋ ์์ ์ฑ์ ํฅ์์ํค๋ ๊ณผ์ ์ ๋ณด์ฌ์ค๋๋ค. Pizza์ Order ๊ฐ์ ์ปค์คํ ํ์ ์ ์ ์ํ๊ณ , ํจ์ ๋งค๊ฐ๋ณ์์ ํ์ ์ ์ง์ ํ๋ฉฐ, ์ค์ฒฉ ๊ฐ์ฒด ํ์ ์ ๋ถ๋ฆฌํ์ฌ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๊ณ , ์ต์ ๋ ํ๋กํผํฐ๋ฅผ ํตํด ์ ์ฐ์ฑ์ ์ ๊ณตํ๋ฉฐ, ๋ฐฐ์ด ํ์ ์ ๋ช ์ํ๊ณ , ๋ถํ์คํ ๊ฐ์ ๋ํ ๋ฐฉ์ด์ ์ฝ๋ฉ์ ์ถ๊ฐํจ์ผ๋ก์จ ์ฝ๋ ๊ฒฐํจ์ ์ปดํ์ผ ์์ ์ ๊ฐ์งํ๊ณ ๋ฐํ์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๋ TS์ ๊ฐ๋ ฅํ ํ์ ์์คํ ์ ํ์ฉ์ ์ข ํฉ์ ์ผ๋ก ์ค๋ช ํฉ๋๋ค.
5. Advanced Type Features ๐
5-1. Literal types ๐ข
๋ฆฌํฐ๋ด ํ์ ์ด๋, ๊ฐ ์์ฒด๋ฅผ ํ์ ์ผ๋ก ์ง์ ํ๋ ๊ฒ์ ๋ปํฉ๋๋ค.
let myName: "Bob" = "Bobby"
const myName2: "Bob" = "Bobby"myName๊ณผ myName2๋ ๋ชจ๋ "Bob" ์์ฒด๊ฐ ํ์ ์ธ๋ฐ ๊ฐ์ "Bobby"์ด๋ฏ๋ก, ์ ์ฝ๋์์๋ ํ์ ๋ถ์ผ์น ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
5-2. Unions ๐ข
๋ฆฌํฐ๋ด ํ์ ์ด ๊ฐ ์์ฒด๊ฐ ํ์ ์ด ๋๋ ์ผ์ด์ค๋ฅผ ๋ปํ๋ค๋ฉด, ์ฌ๋ฌ ๋ฆฌํฐ๋ด ํ์ ์ค ํ๋๋ง ํ์ฉ๋๋ ํ์ ์ ์ ๋์จ ํ์ ์ด๋ผ๊ณ ํฉ๋๋ค.
type User = {
username: string
role: "guest" | "member" | "admin"
}
type UserRole = "guest" | "member" | "admin"
let userRole: UserRole = "member"5-3. Update order status to use literal type unions ๐ข
Order ํ์ ์ status ์์ฑ์ ์ ๋์จ ํ์ ์ ์ ์ฉํฉ์๋ค.
type Order = {
id: number;
pizza: Pizza;
status: "ordered" | "completed";
};์ดํ newOrder์ Order ํ์ ์ ์ ์ฉํฉ๋๋ค.
function placeOrder(pizzaName: string) {
const selectedPizza = menu.find((pizzaObj) => pizzaObj.name === pizzaName);
if (!selectedPizza) {
console.error(`${pizzaName} does not exist in the menu.`);
return;
}
cashInRegister += selectedPizza.price;
const newOrder: Order = {
id: nextOrderId++,
pizza: selectedPizza,
status: "ordered",
};
orderQueue.push(newOrder);
return newOrder;
}order.status๋ complete์์ completed๋ก ๋ณ๊ฒฝํฉ๋๋ค.
function completeOrder(orderId: number) {
const order = orderQueue.find((order) => order.id === orderId);
if (!order) {
console.error(`${orderId} was not found.`);
return;
}
order.status = "completed";
return order;
}5-4. Add ids to pizzas ๐ข
์ด์ Pizza ํ์ ์ id๋ฅผ ์ถ๊ฐํฉ๋๋ค.
type Pizza = {
id: number;
name: string;
price: number;
};menu์ ๋ณ๊ฒฝ๋ Pizza ํ์ ์ ์ ์ฉํฉ๋๋ค.
const menu: Pizza[] = [
{ name: "Margherita", price: 8 },
{ name: "Pepperoni", price: 10 },
{ name: "Hawaiian", price: 10 },
{ name: "Veggie", price: 9 },
];id๋ฅผ ์ถ๊ฐํด์ผ๊ฒ ์ฃ .
const menu: Pizza[] = [
{ id: 1, name: "Margherita", price: 8 },
{ id: 2, name: "Pepperoni", price: 10 },
{ id: 3, name: "Hawaiian", price: 10 },
{ id: 4, name: "Veggie", price: 9 },
];๋ฉ๋ด๊ฐ ์ถ๊ฐ๋๋ ๋ถ๋ถ์๋ id๋ฅผ ์ถ๊ฐํฉ๋๋ค.
addNewPizza({ id: 5, name: "Chicken Bacon Ranch", price: 12 });
addNewPizza({ id: 6, name: "BBQ Chicken", price: 12 });
addNewPizza({ id: 7, name: "Spicy Sausage", price: 11 });5-5. Type Narrowing ๐ข
์ด์ Type Narrowing์ด ๋ฌด์์ธ์ง ์์๋ณด์ฃ .
getPizzaDetail() ํจ์๋ฅผ ์์ฑํ์ต๋๋ค.
function getPizzaDetail(identifier: string | number) {
if (typeof identifier === "string") {
return menu.find(
(pizza) => pizza.name.toLowerCase() === identifier.toLowerCase()
);
} else {
return menu.find((pizza) => pizza.id === identifier);
}
}Type Narrowing ์ด๋ ์ ๋์ธ ํ์ ๋ฑ ๋์ ๋ฒ์์ ํ์ ์์, ์ค์ ์ฝ๋ ํ๋ฆ์ ๋ฐ๋ผ ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก "์ขํ์" ๋ค๋ฃจ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์ ์ฝ๋๋ ์๋ณ์์ ํ์ ์ string ๋๋ number๋ก ์ขํ ๊ฒ์ ๋๋ค.
5-6. Be explicit whenever you can ๐ข
getPizzaDetail() ํจ์๋ฅผ ์กฐ๊ธ ๋ ๋ํ ์ผํ๊ฒ ์์ ํ์ต๋๋ค. ๋ง์ฝ ํด๋น ํจ์๋ก boolean ๊ฐ์ด ๋ค์ด์ค๋ฉด TypeError๊ฐ ์ถ๋ ฅ๋ ๊ฒ์ ๋๋ค.
export function getPizzaDetail(identifier: string | number) {
if (typeof identifier === "string") {
return menu.find(
(pizza) => pizza.name.toLowerCase() === identifier.toLowerCase()
);
} else if (typeof identifier === "number") {
return menu.find((pizza) => pizza.id === identifier);
} else {
throw new TypeError(
"Parameter 'identifier' must be either a string or number."
);
}
}๐จ ์ค๊ฐ ์์ฝ
๋ฆฌํฐ๋ด ํ์ ์ด ๊ฐ ์์ฒด๋ฅผ ํ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ์, ์ ๋์จ ํ์ ์ด ์ฌ๋ฌ ๊ฐ๋ฅํ ๊ฐ ์ค ํ๋๋ฅผ ํ์ฉํ๋ ๋ฐฉ์(์: "ordered" | "completed")์์ ํ์ธํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํ์ ๋ด๋ก์์ ํตํด string ๋๋ number์ ๊ฐ์ ์ ๋์จ ํ์ ์์ ์กฐ๊ฑด๋ฌธ์ ํ์ฉํด ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ์ขํ ์์ ํ๊ฒ ์์ ํ๋ ๋ฐฉ๋ฒ์ ํฌํจํ์ฌ, ๋ช ์์ ์ธ ํ์ ์ง์ ์ด ํ์ ์คํฌ๋ฆฝํธ์ ๊ฐ๋ ฅํ ํ์ ์์ ์ฑ์ ์ต๋ํ ํ์ฉํ๋ ํต์ฌ์์ ํ์ตํ์ต๋๋ค.
6. Function Typing ๐
6-1. Function return types ๐ข
type UserRole = "guest" | "member" | "admin";
type User = {
username: string;
role: UserRole;
};
const users: User[] = [
{ username: "john_doe", role: "member" },
{ username: "minkwan", role: "admin" },
{ username: "guest_user", role: "guest" },
];
function fetchUserDetails(username: string): User {
const user = users.find((user) => user.username === username);
if (!user) {
throw new Error(`User with username ${username} not found.`);
}
return user;
}: User ๋ถ๋ถ์ด ํจ์๊ฐ ๋ฐํํ๋ user์ ํ์
์ ์๋ฏธํฉ๋๋ค.
6-2. TS-specific types: any ๐ข
value์ type์ any๋ก ์ง์ ํ์ต๋๋ค.
let value: any = 1;
value.toUpperCase();
value = "Hi";
value.map();number์ ๋ํด์ toUpperCase()๋ฅผ ์ํํ๋ ค ํ๊ณ , string์ ๋ํด์๋ map()์ ์ ์ฉํ๋ ค ํ๊ณ ์์ต๋๋ค.
any๋ ์ฐ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. TS์ ํ์ ๊ฒ์ฌ์ ์ด์ ์ ๋ฌด๋ ฅํํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋จ, JS๋ฅผ TS๋ก ๋ณ๊ฒฝํ๋ ๊ณผ์ ์์ ๋น์ฅ ๋ชจ๋ ํ์ ์ ์ ์ํ๊ธฐ ์ด๋ ค์ด ์ํฉ์ด๋ผ๋ฉด ์ผ์์ ์ผ๋ก TS ๊ฒ์ฌ ์ฐํ๋ฅผ ์ํด any๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
6-3. Add return type to getPizzaDetail ๐ข
ํจ์์ return type์ ์ ์ฉํ๋ ๊ฒ์๋ ํฐ ์ด๋ ค์์ด ์์ต๋๋ค.
export function getPizzaDetail(identifier: string | number): Pizza | undefined {
if (typeof identifier === "string") {
return menu.find(
(pizza) => pizza.name.toLowerCase() === identifier.toLowerCase()
);
} else if (typeof identifier === "number") {
return menu.find((pizza) => pizza.id === identifier);
} else {
throw new TypeError(
"Parameter 'identifier' must be either a string or number."
);
}
}6-4. Void return type ๐ข
void๋ "์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์"์ ๋ช ์์ ์ผ๋ก ํํํ๋ ํ์ ์ ๋๋ค.
function addNewPizza(pizzaObj: Pizza): void {
menu.push(pizzaObj);
}์ ํจ์๋ menu์ ์๋ก์ด pizza๋ฅผ ์ถ๊ฐํ ๋ฟ ์ด๋ ํ ๊ฐ๋ '๋ฐํ'ํ์ง ์๊ธฐ์ void ํ์ ์ด๋ผ๊ณ ๋ช ์ํด ์ค๋๋ค.
6-5. Add automatic ids to menu items ๐ข
id ์๋ ์ฆ๊ฐ๋ฅผ ์ํด ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
let nextPizzaId = 1;id๋ฅผ ์ฆ๊ฐ์ํค๋ ๋ก์ง์ ์ถ๊ฐํฉ๋๋ค.
function addNewPizza(pizzaObj: Pizza): void {
pizzaObj.id = nextPizzaId++;
menu.push(pizzaObj);
}์ต์ข ๋ฉ๋ด์ ํํ๋ ์๋์ ๊ฐ์ต๋๋ค.
const menu: Pizza[] = [
{ id: nextPizzaId++, name: "Margherita", price: 8 },
{ id: nextPizzaId++, name: "Pepperoni", price: 10 },
{ id: nextPizzaId++, name: "Hawaiian", price: 10 },
{ id: nextPizzaId++, name: "Veggie", price: 9 },
];๐จ ์ค๊ฐ ์์ฝ
TS์ ํจ์์๋ ๋ฐํ ํ์ (User์ ๊ฐ์ ํน์ ํ์ ์ด๋ Pizza | undefined์ฒ๋ผ ์ ๋์จ ํ์ ์ผ๋ก ๋ฐํ๊ฐ ์ง์ )์ ๋ช ์ํ ์ ์์ต๋๋ค. any ํ์ ์ ์ํ์ฑ(ํ์ ๊ฒ์ฌ๋ฅผ ๋ฌด๋ ฅํํ๋ฏ๋ก ๊ฐ๊ธ์ ์ฌ์ฉ ์์ )๊ณผ void ํ์ (์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์๋ ํจ์์ ๋ฐํ ํ์ ๋ช ์)์ ์ค๋ช ํ์ต๋๋ค. ์ ์ํ ๊ฐ๋ ๋ค์ ํ์ฉํด ํผ์ ๋ฉ๋ด ๊ด๋ฆฌ ์์คํ ์์ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ, ํผ์ ์ ๋ณด ์กฐํ, ๋ฉ๋ด ์์ดํ ์ถ๊ฐ ๋ฑ์ ํจ์์ ํ์ ์์ ์ฑ์ ๋ถ์ฌํ๊ณ , ์๋ ์ฆ๊ฐํ๋ ID๋ฅผ ๊ตฌํํ์ฌ ๋ช ์์ ์ธ ํ์ ์ง์ ์ด ์ฝ๋์ ์์ ์ฑ๊ณผ ๊ฐ๋ ์ฑ์ ํฅ์์ํจ ๋ค๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
7. Advanced TypeScript Features ๐
7-1. Utility Types & Partial ๐ข
Utility Types์ TS๊ฐ ์์ฃผ ์ฐ์ด๋ ํ์ ๋ณํ์ ์ฝ๊ฒ ํ ์ ์๋๋ก ์ ๊ณตํ๋ ๊ธฐ๋ณธ ํ์ ์ ๋๋ค.
๊ทธ์ค Partial๋ T ํ์
์ ๋ชจ๋ ์์ฑ์ optional ํ๊ฒ ๋ง๋ค์ด์ค๋๋ค.
type User = {
id: number
username: string
role: "member" | "contributor" | "admin"
}
type UpdatedUser = Partial<User>
const users: User[] = [
{ id: 1, username: "john_doe", role: "member" },
{ id: 2, username: "jane_smith", role: "contributor" },
{ id: 3, username: "alice_jones", role: "admin" },
{ id: 4, username: "charlie_brown", role: "member" },
];
function updateUser(id: number, updates: UpdatedUser) {
// Find the user in the array by the id
const foundUser = users.find(user => user.id === id)
if (!foundUser) {
console.error("User not found!")
return
}
// Use Object.assign to update the found user in place.
Object.assign(foundUser, updates)
}
// Example updates:
updateUser(1, { username: "new_john_doe" });
updateUser(4, { role: "contributor" });
console.log(users)type UpdatedUser = Partial ๋ถ๋ถ์ ์ํด User์ ๋ชจ๋ ์์ฑ์ด optional ํ๊ฒ ๋ฉ๋๋ค.
์ฆ, username ์์ฑ๋ง ํฌํจ๋ ๊ฐ์ฒด๊ฐ ์๋ค๊ณ ํ๋ฉด, ํด๋น ๊ฐ์ฒด๋ฅผ UpdatedUser์ ํ ๋นํ ์ ์๊ฒ ๋๊ณ , ์ด๋ฅผ ํตํด ์ผ๋ถ ํ๋์ ๋ํด์๋ง ์ ๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํด์ง๋๋ค.
7-2. Omit Utility Type ๐ข
Omit๋ TS ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์
์ค ํ๋์
๋๋ค.
T ํ์ ์์ K๋ก ์ง์ ํ ์์ฑ์ ์ ์ธํ ํ์ ์ ๋ฐํํฉ๋๋ค.
type User = {
id: number
username: string
role: "member" | "contributor" | "admin"
}
type UpdatedUser = Partial<User>
let nextUserId = 1
const users: User[] = [
{ id: nextUserId++, username: "john_doe", role: "member" },
{ id: nextUserId++, username: "jane_smith", role: "contributor" }
];
function updateUser(id: number, updates: UpdatedUser) {
const foundUser = users.find(user => user.id === id)
if (!foundUser) {
console.error("User not found!")
return
}
Object.assign(foundUser, updates)
}
// updateUser(1, { username: "new_john_doe" });
// updateUser(4, { role: "contributor" });
function addNewUser(newUser: Omit<User, "id" | "user">): User {
const user: User = {
id: nextUserId++,
...newUser
}
users.push(user)
return user
}
// example usage:
addNewUser({ username: "joe_schmoe", role: "member" })
console.log(users)addNewUser() ํจ์๋ ์๋ก์ด ์ฌ์ฉ์๋ฅผ users ๋ฐฐ์ด์ ์ถ๊ฐํ๋ ํจ์์
๋๋ค. ์ด๋ Omit๋ User ํ์
์์ id์ username ์์ฑ์ ์ ์ธํ ํ์
์ ๋ํ๋
๋๋ค. ์ฆ, ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์ถ๊ฐํ ๋ id์ username์ ์ ์ธํ ๊ฐ์ฒด๋ง ๋ฐ๋๋ก ์ ํํ๊ณ ์์ต๋๋ค.
๋ถํ์ํ ์์ฑ์ ์ ๊ฑฐํ์ฌ, ์ ํจํ ์กฐ์๋ง ํ์ฉํ๊ณ ์ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
7-3. Fix TS warnings with Omit ๐ข
Pizza App์ Omit์ ์ ์ฉํ๋ฉด, ์ฝ๋๊ฐ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
function addNewPizza(pizzaObj: Omit<Pizza, "id">): Pizza {
const newPizza: Pizza = {
id: nextPizzaId++,
...pizzaObj,
};
menu.push(newPizza);
return newPizza;
}addNewPizza({ name: "Chicken Bacon Ranch", price: 12 });
addNewPizza({ name: "BBQ Chicken", price: 12 });
addNewPizza({ name: "Spicy Sausage", price: 11 });7-4. Generics ๐ข
์ ๋ค๋ฆญ(Generic)์ ํจ์, ํด๋์ค, ์ธํฐํ์ด์ค ๋ฑ์ด ์ฌ๋ฌ ํ์ ์์ ์ฌ์ฌ์ฉ๋ ์ ์๋๋ก ๋ง๋๋ TypeScript์ ๊ธฐ๋ฅ์ ๋๋ค. ํ์ ์ ๋์ค์ ๋ฃ์ ์ ์๊ฒ ๋ง๋๋ ํ์ ๋ณ์๋ผ๊ณ ํ ์ ์์ต๋๋ค.
const gameScores = [14, 21, 33, 42, 59]
const favoriteThings = ["raindrops on roses", "whiskers on kittens", "bright copper kettles", "warm woolen mittens"];
const voters = [{ name: "Alice", age: 42 }, { name: "Bob", age: 77 }]
function getLastItem<Type>(array: Type[]): Type | undefined {
return array[array.length - 1]
}
console.log(getLastItem(gameScores))
console.log(getLastItem(favoriteThings))
console.log(getLastItem(voters))์ฝ์์ ๋ณด๋ฉด, getLastItem() ํจ์์ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฐฐ์ด์ ์ ๋ฌํ๋ ๋ชจ์ต์ ํ์ธํ ์ ์์ต๋๋ค. ๊ฐ ๋ฐฐ์ด์ ๋ง์ง๋ง ์์์ ๋ํ ์ ๋ณด๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
๊ธฐ๋ณธ ํํ๋ ์์ ๊ฐ๊ณ , ์ค์ ๋ก ์ ๋ค๋ฆญ ํ์ ์ ์ ๋ฌํ๋ ๊ณผ์ ์ Pizza App ์์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
7-5. Generic functions in the pizza restaurant ๐ข
Pizza App์ ์ ๋ค๋ฆญ ํ์ ์ ์ ์ฉํด ๋ณด๊ฒ ์ต๋๋ค.
function addToArray<T>(array: T[], item: T): T[] {
array.push(item);
return array;
}์ ํจ์๋ array์ item์ ๋ฐ๋๋ฐ์, ์ด ๋์ด ๋์ผํ ํ์ ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค. ์ฌ๊ธฐ์ T๋ ํน์ ํ์ ์ ๋ํ๋ด๋, ๋์ฒด ๊ฐ๋ฅํ ๋ณ์์ ๋๋ค.
addToArray(menu, { id: nextPizzaId++, name: "Chicken Bacon Ranch", price: 12 });
addToArray(orderQueue, { id: nextOrderId++, pizza: menu[2], status: "done" });menu์ ํ์
์ Pizza[]์
๋๋ค. ๋ฐ๋ผ์ T๋ Pizza๋ก ์๋ ์ถ๋ก ๋ฉ๋๋ค.
orderQueue์ ํ์
์ Order[]์
๋๋ค. ๋ฐ๋ผ์ T๋ Order๋ก ์ถ๋ก ๋์ฃ .
7-6. Explicitly type generic function calls ๐ข
๋ช ์์ ์ผ๋ก ์ ๋ค๋ฆญ์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ฝ๋๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ฉด ๋๊ฒ ์ต๋๋ค.
addToArray<Pizza>(menu, { id: nextPizzaId++, name: "Chicken Bacon Ranch", price: 12 })
addToArray<Order>(orderQueue, { id: nextOrderId++, pizza: menu[2], status: "completed" })์ต์ข ์ ์ผ๋ก ์์ฑ๋ Pizza App์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
type Pizza = {
id: number;
name: string;
price: number;
};
type Order = {
id: number;
pizza: Pizza;
status: "ordered" | "completed";
};
let cashInRegister = 100;
let nextOrderId = 1;
let nextPizzaId = 1;
const menu: Pizza[] = [
{ id: nextPizzaId++, name: "Margherita", price: 8 },
{ id: nextPizzaId++, name: "Pepperoni", price: 10 },
{ id: nextPizzaId++, name: "Hawaiian", price: 10 },
{ id: nextPizzaId++, name: "Veggie", price: 9 },
];
const orderQueue: Order[] = [];
function addNewPizza(pizzaObj: Pizza): Pizza {
menu.push(pizzaObj);
return pizzaObj;
}
function placeOrder(pizza: Pizza): Order | undefined {
const newOrder: Order = {
id: nextOrderId++,
pizza: pizza,
status: "ordered",
};
orderQueue.push(newOrder);
cashInRegister += pizza.price;
return newOrder;
}
function addToArray<T>(array: T[], item: T): T[] {
array.push(item);
return array;
}
addToArray<Pizza>(menu, {
id: nextPizzaId++,
name: "Chicken Bacon Ranch",
price: 12,
});
addToArray<Order>(orderQueue, {
id: nextOrderId++,
pizza: menu[2],
status: "completed",
});
console.log(menu);
console.log(orderQueue);
function completeOrder(orderId: number): Order | undefined {
const order = orderQueue.find((order) => order.id === orderId);
if (!order) {
console.error(`${orderId} was not found in the orderQueue`);
return;
}
order.status = "completed";
return order;
}
export function getPizzaDetail(identifier: string | number): Pizza | undefined {
if (typeof identifier === "string") {
return menu.find(
(pizza) => pizza.name.toLowerCase() === identifier.toLowerCase()
);
} else if (typeof identifier === "number") {
return menu.find((pizza) => pizza.id === identifier);
} else {
throw new TypeError(
"Parameter `identifier` must be either a string or a number"
);
}
}๐จ ์ค๊ฐ ์์ฝ
TS์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ธ ์ ํธ๋ฆฌํฐ ํ์ ๊ณผ ์ ๋ค๋ฆญ์ ๊ดํ ๋ด์ฉ์ด์์ต๋๋ค.
Partial๋ ํ์ ์ ๋ชจ๋ ์์ฑ์ ์ ํ์ ์ผ๋ก ๋ง๋ค์ด ์ผ๋ถ ํ๋๋ง ์ ๋ฐ์ดํธํ ์ ์๊ฒ ํฉ๋๋ค.Omit๋ ํน์ ์์ฑ์ ์ ์ธํ ์๋ก์ด ํ์ ์ ์์ฑํ์ฃ . ๋์ผ๋ก,์ ๋ค๋ฆญ์ ํจ์๋ ํด๋์ค๊ฐ ๋ค์ํ ํ์ ์์ ์ฌ์ฌ์ฉ๋ ์ ์๋๋ก ํ์ ๋ณ์๋ฅผ ํ์ฉํ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ด๋ฅผ ํตํด ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.
8. Conclusion ๐
ํ์ ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ํ์ตํ๋ฉด์ ๋ง์ ๋ด์ฉ์ ์ตํ์ง๋ง, ์์ง ๋ค๋ฃจ์ง ๋ชปํ ๋ถ๋ถ๋ ๋ง์ ์ถ๊ฐ์ ์ธ ํ์ต์ด ํ์ํ๋ค๋ ์ ์ ๋๊ผ์ต๋๋ค.
ํ์ ์คํฌ๋ฆฝํธ๋ ์ฝ๋์ ํ์ ์์ ์ฑ์ ๋์ด๊ธฐ ์ํ ๋๊ตฌ์ ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ดํด๋ณธ ๊ธฐ๋ฅ๋ค์ ๋ฐ๋์ ๋ชจ๋ ์ ์ฉํด์ผ ํ๋ ๊ฒ์ ์๋๋๋ค. ๊ธฐ์ ์์ฒด๊ฐ ๋ชฉ์ ์ด ๋์ด์๋ ์ ๋ฉ๋๋ค.
์ค์ํ ๊ฒ์ ํ๋ก์ ํธ์ ํน์ฑ๊ณผ ์ํฉ์ ๋ง๊ฒ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ ํ ํ์ฉํจ์ผ๋ก์จ ์ ์ฒด์ ์ธ ์์ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ด๋ ๊ฒ์ ๋๋ค.
More to read
Amazon VPC Architecture ์ดํดํ๊ธฐ
์๋ก์ด ํ๋ก์ ํธ๋ฅผ ๊ธฐํํ๋ฉฐ, ๊ฐ๋ฐ์์ ๋ฌด์์ ๊ฐ์ฅ ๋จผ์ ๊ณ ๋ฏผํด์ผ ํ๋์ง ๋ค์ ๋์๋ณด๊ฒ ๋์์ต๋๋ค.ํ๋๋ ํ๋ก ํธ์๋๊ฐ ๋ชจ๋ ์ค๊ณ์ ์ถ๋ฐ์ ์ด๋ผ๊ณ ๋ฏฟ์์ต๋๋ค. ์ ์ ๊ฐ ๋ฌด์์ ๋ณด๊ณ , ์ด๋ค ํ๋ฆ์์ ๋จธ๋ฌด๋ฅด๊ณ ์ดํํ๋์ง์ ๋ํ ์ดํด ์์ด ์๋น์ค๋ฅผ ๋ง๋ ๋ค๋ ๊ฑด ๋ถ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํ๊ธฐ
'์์ฌ์ดํธ'ํ๋ก ํธ์๋ ๊ด์ ์ผ๋ก ์๊ณ ๋ฆฌ์ฆ ์ดํดํ๊ธฐ
์ค๋๋ง์ ๋ฐฉ๋ฒ๋ก ์ ๊ดํ ๊ธ์ ์ฐ๊ฒ ๋์์ต๋๋ค. ์ต๊ทผ ์ํฉ์ ์ด๋ ์ต๋๋ค. SSAFY์์๋ ํ๋ฃจ์ ์์ฒญ๋ ์์ ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ๋ค์ ๊ณผ์ ๋ก ์ํํ๊ฒ ๋ฉ๋๋ค. ๊ทธ ๊ณผ์ ์์, '๊ตฌํ๋ ฅ'์ด ๋งค์ฐ ๋จ์ด์ง๋ค๋ ์๊ฐ์ด ๋ค์์ต๋๋ค. ์์ ํ ์ด๋ ค์ด ๋ฌธ์ ๋ผ๋ฉด '์์ฌ์'์ด๋ผ๋ ๊ฐ์ ์กฐ์ฐจ ๋๋ผ์ง
SubnetVPC ์ค๊ณ์ ์์: IP์ Subnet
๋ฐ๋ณต๋๋ ๋ฃจํด ์์์ ์ป์ ์์ ๊ฐ์ ๋ฐํ ์ผ์, ์ด์ ๋ ๊ธฐ์ ์ ์คํํธ๋ผ์ ๋ํ๊ธฐ ์ํ ๊ฐ์ธ ํ๋ก์ ํธ์ ์ฐฉ์ํ๊ณ ์ ํฉ๋๋ค.์ด๋ฒ ํ๋ก์ ํธ์ ๋ชฉํ๋ ๋จ์ํ ํฌํธํด๋ฆฌ์ค ๊ตฌ์ถ์ ๋์ด, ์ค์ ์๋น์ค ์์ค์ ๋ธ๋ก๊ทธ ์์คํ ๊ตฌํ๊ณผ ๋ค๊ตญ์ด ์ฒ๋ฆฌ ์ ์ฉ ๋ฑ ์ค๋ฌด์ ๊ฐ๊น์ด ์ญ๋์ ํ ๋จ๊ณ