๐ ํ์ ์คํฌ๋ฆฝํธ
๊ณต๋ถ๋ฐฉ ์๋ฃ๋ keysub๊ฐ AI๋ฅผ ํ์ฉํด ์์ฑยทํธ์งํ์ต๋๋ค.
1. Introduction ๐
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
1.1 ํ์ ์คํฌ๋ฆฝํธ๋ ๋ฌด์์ธ๊ฐ? ๐ค
ํ์ ์คํฌ๋ฆฝํธ(TypeScript)๋ ๋ง์ดํฌ๋ก์ํํธ์์ ๊ฐ๋ฐํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ก, ์ฝ๊ฒ ๋งํด "์๋ฐ์คํฌ๋ฆฝํธ์ 'ํ์ (ํ์)'์ ์ ํ ์ธ์ด"์ ๋๋ค.
1.2 ์๋ฐ์คํฌ๋ฆฝํธ์ ์์ ์งํฉ(Superset)์ผ๋ก์์ ์์น ๐
1.2.1. ์์ ์งํฉ(Superset)์ด๋ ์๋ฏธ
์ํ์์ ๋งํ๋ ํฌํจ ๊ด๊ณ๋ฅผ ์๊ฐํ๋ฉด ์ฝ์ต๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ '์์ ์'์ด๋ผ๋ฉด, ํ์ ์คํฌ๋ฆฝํธ๋ ๊ทธ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์์ ํ ํฌํจํ๋ '๋ ํฐ ์'์ ๋๋ค. * ํธํ์ฑ: ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ ์ ํจํ ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋์ ๋๋ค. ์ฆ, ๊ธฐ์กด .js ํ์ผ์ ํ์ฅ์๋ง .ts๋ก ๋ฐ๊ฟ๋ ๋ฌธ์ ์์ด ์๋ํฉ๋๋ค. * ํ๋ฌ์ค ์ํ: ์๋ฐ์คํฌ๋ฆฝํธ์ ๊ธฐ์กด ๋ฌธ๋ฒ ์์ '์ ์ ํ์ ์์คํ '์ด๋ผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ถ๊ฐํ ๊ฒ์ ๋๋ค.
1.2.2. ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ ํ์ ์ ์น์์๊น?
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋งค์ฐ ์ ์ฐํ์ง๋ง, ๊ท๋ชจ๊ฐ ์ปค์ง๋ฉด ์ด๋์ ์ด๋ค ์๋ฌ๊ฐ ๋ ์ง ์์ธกํ๊ธฐ ์ด๋ ต๋ค๋ ๋จ์ ์ด ์์ต๋๋ค. ํ์ ์คํฌ๋ฆฝํธ๋ ์ด๋ฅผ ๋ณด์ํฉ๋๋ค. * ์๋ฌ ์ฌ์ ๋ฐฉ์ง: ์ฝ๋๋ฅผ ์คํํ๊ธฐ ์ (์ปดํ์ผ ๋จ๊ณ)์ ์คํ๋ ์๋ชป๋ ๋ฐ์ดํฐ ํ์ ์ฌ์ฉ์ ์ก์๋ ๋๋ค. * ๊ฐ์ด๋ ์ญํ : ๋ณ์๋ ํจ์๊ฐ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋์ง ๋ช ์ํ๊ธฐ ๋๋ฌธ์, ๋๋ฃ ๊ฐ๋ฐ์(ํน์ ๋ฏธ๋์ ๋)๊ฐ ์ฝ๋๋ฅผ ํจ์ฌ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค. * ๋๊ตฌ ์ง์: ์๋ ์์ฑ ๊ธฐ๋ฅ์ด ๋น์ฝ์ ์ผ๋ก ์ข์์ ธ์ ๊ฐ๋ฐ ์๋์ ์ ํ๋๊ฐ ์ฌ๋ผ๊ฐ๋๋ค.
1.2.3. ๋์ ๋ฐฉ์: ๋ธ๋ผ์ฐ์ ๋ ์ดํดํ์ง ๋ชปํ๋ค? โ๏ธ
๋ธ๋ผ์ฐ์ ๋ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ง์ ์ฝ์ง ๋ชปํฉ๋๋ค. ๊ทธ๋์ '์ปดํ์ผ(๋๋ ํธ๋์คํ์ผ)' ๊ณผ์ ์ด ํ์ํฉ๋๋ค.
1. .ts ํ์ผ๋ก ์ฝ๋๋ฅผ ์งญ๋๋ค
2. ์ปดํ์ผ๋ฌ๊ฐ ํ์
์ ์ฒดํฌํ๊ณ ์๋ฌ๋ฅผ ํ์ธํฉ๋๋ค
3. ์ด์์ด ์์ผ๋ฉด ํ์
์ ์ ๊ฑฐํ ์์ .js ํ์ผ๋ก ๋ณํํฉ๋๋ค
4. ๋ธ๋ผ์ฐ์ ๋ ์ด ์ต์ข
์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ์คํํฉ๋๋ค
1.3 ๋์ ํ์ ์ธ์ด(JS)์ ์ ์ ํ์ ์ธ์ด(TS)์ ์ฐจ์ด โ๏ธ
๋์ ํ์ (JS)๊ณผ ์ ์ ํ์ (TS)์ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ 'ํ์ ์ ์ธ์ ๊ฒฐ์ ํ๋๋'์ '์๋ฌ๋ฅผ ์ธ์ ๋ฐ๊ฒฌํ๋๋'์ ์์ต๋๋ค.
| ๊ตฌ๋ถ | ์๋ฐ์คํฌ๋ฆฝํธ (Dynamic Type) | ํ์ ์คํฌ๋ฆฝํธ (Static Type) |
|---|---|---|
| ํ์ ๊ฒฐ์ ์์ | ์คํ ์(Runtime) ๋ณ์์ ๊ฐ์ด ํ ๋น๋ ๋ ์๋์ผ๋ก ๊ฒฐ์ ๋จ | ์ฝ๋ ์์ฑ ์(Compile time) ๊ฐ๋ฐ์๊ฐ ํ์ ์ ์ง์ ๋ช ์ํจ |
| ์๋ฌ ํ์ธ ์์ | ํ๋ก๊ทธ๋จ์ ์คํํด ๋ด์ผ ์๋ฌ๋ฅผ ์ ์ ์์ | ํ๋ก๊ทธ๋จ์ ์คํํ๊ธฐ ์ ์ปดํ์ผ ๋จ๊ณ์์ ์๋ฌ๋ฅผ ์ก์ |
| ์ ์ฐ์ฑ/์์ ์ฑ | ๋งค์ฐ ์ ์ฐํ์ง๋ง, ์์์น ๋ชปํ ํ์ ์๋ฌ ๋ฐ์ ํ๋ฅ ์ด ๋์ | ์๊ฒฉํ์ง๋ง, ์ฝ๋์ ์์ ์ฑ๊ณผ ์์ธก ๊ฐ๋ฅ์ฑ์ด ๋์ |
1.3.1. ์๋ฐ์คํฌ๋ฆฝํธ (๋์ ํ์ ) ๐
๋ณ์ ํ๋์ ์ซ์๋ ๋ฃ์๋ค๊ฐ, ๋ฌธ์์ด๋ ๋ฃ์ ์ ์์ต๋๋ค.
let value = 10; // ์ฒ์์ ์ซ์
value = "์๋
"; // ๊ฐ์๊ธฐ ๋ฌธ์์ด๋ก ๋ฐ๊ฟ๋ OK (์คํ ์ ๊น์ง ๋ฌธ์ ๋ชจ๋ฆ)
1.3.2. ํ์ ์คํฌ๋ฆฝํธ (์ ์ ํ์ ) ๐ก๏ธ
๋ณ์๋ฅผ ๋ง๋ค ๋ ์ด๋ค ํ์ ์ด ๋ค์ด๊ฐ์ง ๋ฏธ๋ฆฌ ์ฝ์ํฉ๋๋ค.
let value: number = 10;
value = "์๋
"; // ์๋ฌ ๋ฐ์! "์ซ์ ํ์
์ ๋ฌธ์์ด์ ๋ฃ์ ์ ์์ต๋๋ค."
2. ๊ธฐ๋ณธ ํ์ (Basic Types) ๐
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
2.1 ๊ธฐ๋ณธ ์๋ฃํ ๐
2.1.1. string: ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ
let userName: string = "Alice";
let greeting: string = `Hello, ${userName}`; // ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด๋ ๊ฐ๋ฅ
2.1.2. number: ์ ์, ์ค์ ๊ตฌ๋ถ ์์ด ๋ชจ๋ ์ซ์ ์ ์ฅ
let age: number = 25;
let pi: number = 3.14;
2.1.3. boolean: ์ฐธ(true) ๋๋ ๊ฑฐ์ง(false)
let isLoggedIn: boolean = true;
let hasToken: boolean = false;
2.1.4. null & undefined
๋ณดํต ๋จ๋ ์ผ๋ก ์ฐ๊ธฐ๋ณด๋ค "๊ฐ์ด ์์"์ ๋ช ์ํ ๋ ์ฌ์ฉํฉ๋๋ค.
let empty: null = null;
let notFound: undefined = undefined;
2.2 ๋ฐฐ์ด(Array)๊ณผ ํํ(Tuple) ๐๏ธ
๋ฐฐ์ด๊ณผ ํํ์ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์กฐํํ ๋ ํต์ฌ์ ์ธ ์ญํ ์ ํฉ๋๋ค. ํนํ ๋ฐฐ์ด์ ๊ฐ์ ํ์ ์ ๋ชฉ๋ก์, ํํ์ ์ ํด์ง ์์์ ๊ฐ์์ ๋ชฉ๋ก์ ๋ค๋ฃฐ ๋ ์ฌ์ฉํฉ๋๋ค.
2.2.1 ๋ฐฐ์ด ํ์ ์ ์ธ ๋ฐฉ์: type[] vs Array
// ๋ฐฉ๋ฒ 1: ํ์
[] (๊ฐ์ฅ ๋ง์ด ์ฐ์)
const productList: string[] = ["์์ดํฐ", "๊ฐค๋ญ์", "๋งฅ๋ถ"];
// ๋ฐฉ๋ฒ 2: Array<ํ์
> (์ ๋ค๋ฆญ ๋ฐฉ์)
const priceList: Array<number> = [1000, 2000, 3000];
2.2.2 ๊ฐ์ฒด ๋ฐฐ์ด ๐ฆ
๋ณดํต ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ 'ํ์ ๋ชฉ๋ก', '์ํ ๋ฆฌ์คํธ' ๊ฐ์ ํํ
2.2.2.1. ๊ฐ์ฒด ๋ฐฐ์ด์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ : [1. ๊ฐ์ฒด์ ์๊น์ ์ ์] โ [2. ๋ฐฐ์ด์ ์ ์ฉ]
- interface์ []์ ์กฐํฉ (๊ฐ์ฅ ๋ง์ด ์ฐ์)
// 1. ๊ฐ์ฒด์ ์ค๊ณ๋(Interface) ์์ฑ
interface User {
id: number;
name: string;
}
// 2. ํด๋น ํ์
์ ๋ฐฐ์ด์ ์ ์ฉํ๊ธฐ
const users: User[] = [
{ id: 1, name: "Kim" },
{ id: 2, name: "Lee" }
];
users.push({ id: 3, name: "Park" }); // ์์ ๋กญ๊ฒ ์ถ๊ฐ ๊ฐ๋ฅ
- type ๋ณ์นญ๊ณผ Array<>์ ์กฐํฉ
type User = {
id: number;
name: string;
};
const users: Array<User> = [
{ id: 1, name: "Kim" }
];
- ์ ์ฐํ ํ์ ์ ์ (์ ํ์ ์์ฑ). ์ด๋๋ ?๋ฅผ ์ฌ์ฉํฉ๋๋ค
interface User {
id: number;
name: string;
email?: string; // ์ด๋ฉ์ผ์ ๊ฐ์ด ์๋ ๊ฒฝ์ฐ String, ์์ผ๋ฉด undefined (undefined ๊ฐ๋ฅ)
}
const userList: User[] = [
{ id: 1, name: "Kim", email: "kim@test.com" },
{ id: 2, name: "Lee" } // email์ด ์์ด๋ ์๋ฌ๊ฐ ๋์ง ์์
];
- ์ฝ๊ธฐ ์ ์ฉ ๋ฐฐ์ด (Readonly)
const colors: readonly string[] = ["Red", "Blue"];
colors.push("Green"); // ์๋ฌ! (์ถ๊ฐ ๋ถ๊ฐ๋ฅ)
2.2.3 ํํ (Tuple) ๐ฑ
-
ํํ(Tuple) ์ ํ๋ง๋๋ก '์์์ ๊ฐ์๊ฐ ์ ํด์ง ๋ฐ์ดํฐ ๋ฌถ์'์ ๋ปํ๋ ์ํ/์ปดํจํฐ ๊ณตํ ์ฉ์ด์ ๋๋ค. ์ผ์์ํ๋ก ๋น์ ํ์๋ฉด '์ธํธ ๋ฉ๋ด' ์ ๋น์ทํฉ๋๋ค.
"ํ๋ฒ๊ฑฐ ์ธํธ"๋ผ๊ณ ํ๋ฉด[ํ๋ฒ๊ฑฐ, ์ฝ๋ผ, ๊ฐ์ํ๊น]์ด๋ผ๋ ์์์ ๊ตฌ์ฑ์ด ๋ฑ ์ ํด์ ธ ์๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. -
ํ์ ์คํฌ๋ฆฝํธ์์ ํํ์ ๋ฐฐ์ด์ ํ์ ํ์ ์ผ๋ก, ์์์ ๊ฐ์๊ฐ ๊ณ ์ ๋๊ณ ๊ฐ ์์์ ํ์ ์ด ๋ฏธ๋ฆฌ ์ ํด์ง ๋ฐฐ์ด์ ์๋ฏธํฉ๋๋ค.
2.2.3.1 ๊ธฐ๋ณธ ์ ์ธ๊ณผ ํ ๋น ๐
๊ฐ ์ธ๋ฑ์ค์ ๋ค์ด๊ฐ ํ์ ์ ์์๋๋ก ๋ช ์ํฉ๋๋ค.
let person: [string, number];
person = ["Alice", 30]; // โ
OK
// person = [30, "Alice"]; // โ Error: ์์๊ฐ ๋ค๋ฆ
// person = ["Alice", 30, true]; // โ Error: ์ ํด์ง ๊ธธ์ด๋ฅผ ์ด๊ณผํจ
2.2.3.2 ์ ํ์ ์์ (Optional Elements) โ
ํน์ ์์๊ฐ ์์ ์๋ ์๊ณ ์์ ์๋ ์๋ค๋ฉด ?๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋จ, ์ ํ์ ์์๋ ํญ์ ๋ค์ชฝ์ ์์นํด์ผ ํฉ๋๋ค.
let point: [number, number, number?];
point = [10, 20]; // โ
OK
point = [10, 20, 30]; // โ
OK
2.2.3.3 ๋๋จธ์ง ์์ (Rest Elements) ๐
ํํ์ ์ผ๋ถ๋ถ๋ง ํ์ ์ ์ง์ ํ๊ณ , ๋๋จธ์ง๋ ๊ฐ๋ณ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
let logger: [string, ...number[]];
logger = ["Error", 404, 500, 502]; // โ
์ฒซ ๋ฒ์งธ๋ ๋ฌธ์์ด, ๋๋จธ์ง๋ ์ซ์ ๋ฐฐ์ด
2.2.3.4 ์ฝ๊ธฐ ์ ์ฉ ํํ (Readonly Tuple) ๐
ํํ์ ์ผ๋ฐ ๋ฐฐ์ด์ฒ๋ผ push๋ pop์ด ๊ฐ๋ฅํ์ฌ ๊ณ ์ ๋ ๊ธธ์ด๊ฐ ๊นจ์ง ์ํ์ด ์์ต๋๋ค. ์ด๋ฅผ ์์ ํ ๋ฐฉ์งํ๋ ค๋ฉด readonly๋ฅผ ๋ถ์ฌ์ผ ํฉ๋๋ค.
const readOnlyTuple: readonly [number, string] = [1, "Fixed"];
// readOnlyTuple.push(2); // โ Error: 'readonly' ํ์
์๋ push ๋ฉ์๋๊ฐ ์์
2.2.3.5 ๋ผ๋ฒจ๋ง๋ ํํ (Labeled Tuple Elements) ๐ท๏ธ [๊ถ์ฅ]
๊ฐ ์์๊ฐ ๋ฌด์์ ์๋ฏธํ๋์ง ์ด๋ฆ์ ๋ถ์ฌ ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.
type UserInfo = [id: number, name: string, email: string];
const user: UserInfo = [1, "Kim", "kim@example.com"];
2.2.3.6 ๐ก ํํ vs ์ธํฐํ์ด์ค/๊ฐ์ฒด โ๏ธ
๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ๊ฐ์ฒด({})๋ฅผ ์ธ์ง ํํ([])์ ์ธ์ง ๊ณ ๋ฏผ๋๋ค๋ฉด ๋ค์ ๊ธฐ์ค์ ์ฐธ๊ณ ํ์ธ์.
- ๊ฐ์ฒด: ๋ฐ์ดํฐ์ ์๋ฏธ๊ฐ ํค(Key) ์ด๋ฆ์ผ๋ก ์ค๋ช ๋์ด์ผ ํ ๋ (๋๋ถ๋ถ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ).
- ํํ: ์์ ์์ฒด๊ฐ ์ค์ํ ์๋ฏธ๋ฅผ ๊ฐ๊ฑฐ๋, 2~3๊ฐ์ ์งง์ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ๋๊ธธ ๋ (์: ์ขํ
[x, y], ์ํ ๊ด๋ฆฌ[state, setter]).
๐ 2.3 ์ถ๊ฐ๋ ํ์ (TS ์ ์ฉ ์์คํ ํ์ )
๐ฆ 2.3.1 ์ด๊ฑฐํ(Enum)
Enum(์ด๊ฑฐํ)์ ์ฐ๊ด๋ ์์ดํ
๋ค์ ํ๋์ ์งํฉ์ผ๋ก ๋ฌถ์ด ๊ด๋ฆฌํ ๋ ์ฌ์ฉํฉ๋๋ค.
์ฝ๋์ ๊ฐ๋
์ฑ์ ๋์ด๊ณ , ์ ํด์ง ๊ฐ ์ธ์ ๋ค๋ฅธ ๊ฐ์ด ๋ค์ด์ค์ง ๋ชปํ๊ฒ ์ ํํ๋ ์ญํ ์ ํฉ๋๋ค.
๐ฆ 2.3.1.1 ์ํ ์ฝ๋ ๊ด๋ฆฌ
๊ฐ์ฅ ๋ํ์ ์ธ ์์๋ ์ฃผ๋ฌธ ์ํ, ์ ์ ๊ถํ, HTTP ์๋ต ์ฒ๋ฆฌ ๋ฑ์ ๋๋ค.
// 1. ์ ์ธ: ์ฃผ๋ฌธ ์ํ๋ฅผ ์ ์
enum OrderStatus {
Pending = "PENDING", // ๋๊ธฐ ์ค
Shipped = "SHIPPED", // ๋ฐฐ์ก ์ค
Delivered = "DELIVERED", // ์๋ฃ
Cancelled = "CANCELLED" // ์ทจ์
}
// 2. ํ์ฉ: ํจ์ ์ธ์์ ํ์
์ผ๋ก ์ฌ์ฉ
function updateOrderStatus(id: number, status: OrderStatus) {
console.log(`์ฃผ๋ฌธ๋ฒํธ ${id}์ ์ํ๋ฅผ ${status}๋ก ๋ณ๊ฒฝํฉ๋๋ค.`);
}
// ์ฌ์ฉ ์์
updateOrderStatus(1024, OrderStatus.Shipped);
// ์๋ฌ ๋ฐ์: ์ ์๋์ง ์์ ๋ฌธ์์ด์ ๋ฃ์ ์ ์์
// updateOrderStatus(1025, "READY");
โก 2.3.1.2 const enum
const๋ฅผ ๋ถ์ด๋ฉด ์ปดํ์ผ ์์ ์ Enum ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ง ์๊ณ ๊ฐ์ ์ง์ ์ฑ์ ๋ฃ์ด ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ํจ์ฌ ๊ฐ๋ฒผ์์ง๋๋ค.
const enum Role {
Admin = "ADMIN",
User = "USER"
}
โ๏ธ 2.3.1.3 ์ซ์ํ Enum๊ณผ ๋ฌธ์์ด Enum์ ์ฐจ์ด
๋ ๋ฐฉ์์ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ '๊ฐ์ด ์๋์ผ๋ก ํ ๋น๋๋๊ฐ'์ '๋๋ฒ๊น ์ ์ผ๋ง๋ ๋ช ํํ๊ฐ'์ ์์ต๋๋ค.
1๏ธโฃ ๊ฐ์ ์๋ ํ ๋น (Auto-incrementing) * ์ซ์ํ Enum: ๊ฐ์ ์๋ตํ๋ฉด 0๋ถํฐ ์์ํด์ 1์ฉ ์๋์ผ๋ก ์ฆ๊ฐํฉ๋๋ค. * ๋ฌธ์์ด Enum: ์๋ ํ ๋น์ด ์์ต๋๋ค. ๋ชจ๋ ๋ฉค๋ฒ์ ๊ฐ์ ์ผ์ผ์ด ์๋์ผ๋ก ๋ฃ์ด์ค์ผ ํฉ๋๋ค.
// ์ซ์ํ: 0, 1, 2 ์๋ ํ ๋น
enum Direction { Up, Down, Left }
// ๋ฌธ์์ด: ๋ฐ๋์ ๋ช
์ํด์ผ ํจ
enum DirectionStr {
Up = "UP",
Down = "DOWN",
Left = "LEFT"
}
2๏ธโฃ ๋๋ฒ๊น
๊ณผ ๋ก๊ทธ (๋ก๊ทธ์ ๊ฐ๋
์ฑ)
* ์ซ์ํ: ๋ก๊ทธ๋ฅผ ์ฐ์ผ๋ฉด 0, 1 ๊ฐ์ ์ซ์๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. ์ฝ๋๋ฅผ ์ง ์ฌ๋์ด ์๋๋ฉด ์ด๊ฒ ์ด๋ค ์ํ์ธ์ง ์๊ธฐ ์ด๋ ต์ต๋๋ค.
* ๋ฌธ์์ด: ๋ก๊ทธ์ "UP", "DOWN" ์ฒ๋ผ ์๋ฏธ๊ฐ ๋ช
ํํ ํ
์คํธ๊ฐ ์ฐํ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ณด๊ฑฐ๋ ์๋ฌ ๋ก๊ทธ๋ฅผ ๋ถ์ํ ๋ ํจ์ฌ ์ ๋ฆฌํฉ๋๋ค.
3๏ธโฃ ์ญ๋ฐฉํฅ ๋งคํ (Reverse Mapping)
* ์ซ์ํ: ์ด๋ฆ์ผ๋ก ๊ฐ์ ์ฐพ์ ์๋ ์๊ณ , ๊ฐ์ผ๋ก ์ด๋ฆ์ ์ฐพ์ ์๋ ์์ต๋๋ค. (Direction[0] -> "Up")
* ๋ฌธ์์ด: ์ด๋ฆ์ผ๋ก ๊ฐ๋ง ์ฐพ์ ์ ์์ต๋๋ค. ์ญ๋ฐฉํฅ ๋งคํ์ ์ง์ํ์ง ์์ ๋ ์์ ํ๊ณ ์๊ฒฉํฉ๋๋ค.
๐ 2.3.2 Any (๋ฌด์์ด๋ ํ์ฉ)
๋ชจ๋ ํ์ ์ ๊ฒ์ฌ๋ฅผ ํด์ ํฉ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ค๋ฅผ ๋ฐ ์๊ฒ ๋ง๋ค์ด์ ํธ๋ฆฌํ์ง๋ง, ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๋ ์๋ฏธ๊ฐ ์ฌ๋ผ์ง๋ฏ๋ก ์ต๋ํ ์ง์ํด์ผ ํฉ๋๋ค.
let value: any = 10;
value = "์๋
"; // ์๋ฌ ์ ๋จ
value.toUpperCase(); // ์๋ฌ ์ ๋จ (๋ง์ฝ ์ซ์์๋ค๋ฉด ๋ฐํ์ ์๋ฌ ๋ฐ์ ์ํ)
๐ 2.3.3 Unknown (์์ ํ Any)
any์ฒ๋ผ ์ด๋ค ํ์ ์ ๊ฐ๋ ์ ์ฅํ ์ ์์ง๋ง, ์ฌ์ฉํ๊ธฐ ์ ์ ๋ฐ๋์ ํ์ ์ ํ์ธ(ํ์ ๊ฐ๋)ํด์ผ ํฉ๋๋ค.any๋ณด๋ค ํจ์ฌ ์์ ํฉ๋๋ค.- API ์๋ต์ฒ๋ผ ๋ญ๊ฐ ์ฌ์ง ์ง์ง ๋ชจ๋ฅผ ๋ ์ฌ์ฉํฉ๋๋ค.
let value: unknown = "Hello";
// value.toUpperCase(); // ์๋ฌ! (unknown ํ์
์ด๋ผ ๋ฐ๋ก ์ฌ์ฉ ๋ถ๊ฐ)
if (typeof value === "string") {
value.toUpperCase(); // ํ์
ํ์ธ์ ํ์ผ๋ฏ๋ก ์ด์ ์ฌ์ฉ ๊ฐ๋ฅ!
}
๐จ 2.3.4 Void (๋น์ด์์)
- ํจ์๊ฐ ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
return๋ฌธ์ด ์๋ ํจ์๋, ๋จ์ํ ์ฝ์๋ง ์ฐ๋ ํจ์์์ ์ฌ์ฉํฉ๋๋ค.
function sayHi(): void {
console.log("Hi!");
// return 1; // ์๋ฌ! ๋ฐํ๊ฐ์ด ์์ผ๋ฉด ์ ๋จ
}
๐ซ 2.3.5 Never (์ ๋ ์ผ์ด๋ ์ ์์)
ํจ์๊ฐ ๋๋์ง ์๊ฑฐ๋, ํญ์ ์๋ฌ๋ฅผ ๋์ ธ์ ๋ฐํ๊ฐ์ด๋ผ๋ ๊ฐ๋
์์ฒด๊ฐ ์กด์ฌํ ์ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
๋ฌดํ ๋ฃจํ, ์๋์ ์ธ ์๋ฌ ๋ฐ์ ํจ์์์ ์ฌ์ฉ๋ฉ๋๋ค.
function throwError(msg: string): never {
throw new Error(msg); // ํจ์๊ฐ ๋๋์ง ์๊ณ ์ฌ๊ธฐ์ ๋ฉ์ถค
}
function infiniteLoop(): never {
while (true) {} // ์์ํ ์คํ๋จ
}
3. ์ธํฐํ์ด์ค์ ํ์ ๋ณ์นญ (Interface & Type Alias) ๐ท๏ธ
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
3.1 Interface์ ๊ธฐ๋ณธ ๊ตฌ์กฐ ๐๏ธ
์ธํฐํ์ด์ค๋ interface ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ํ๋ฉฐ, ๊ฐ์ฒด๊ฐ ๊ฐ์ ธ์ผ ํ ์์ฑ(Property)๊ณผ ๋ฉ์๋(Method)๋ฅผ ๋ช
์ํฉ๋๋ค.
interface User {
id: number;
name: string;
email: string;
}
const worker: User = {
id: 1,
name: "Kim",
email: "kim@example.com"
};
3.2 ๊ฐ์ฒด์ ํํ(Shape) ์ ์ ๐
'๊ฐ์ฒด์ ํํ(Shape)๋ฅผ ์ ์ํ๋ค'๋ ๋ง์, ํด๋น ๊ฐ์ฒด๊ฐ ์ด๋ค ์ด๋ฆ์ ํค(Key)๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ๊ทธ ํค์ ์ด๋ค ํ์ ์ ๊ฐ(Value)์ด ๋ด๊ฒจ์ผ ํ๋์ง๋ฅผ ๋ฏธ๋ฆฌ ๊ฒฐ์ ํด๋๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
3.2.1 ์ค๊ณ๋(Blueprint)๋ก์์ ์ญํ ๐
ํ์ค ์ธ๊ณ์์ ๊ฑด๋ฌผ์ ์ง์ ๋ ์ค๊ณ๋๊ฐ ํ์ํ๋ฏ, ์ฝ๋์์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ๋ "์ด ๊ฐ์ฒด๋ ๋ฐ๋์ id๋ ์ซ์์ฌ์ผ ํ๊ณ , name์ ๋ฌธ์์ด์ด์ด์ผ ํด" ๋ผ๊ณ ๊ท์ ํ๋ ๊ฒ์ ๋๋ค.
// 1. ํํ(Shape)๋ฅผ ์ธํฐํ์ด์ค๋ก ์ ์
interface Product {
name: string;
price: number;
}
// 2. ์ ์๋ ํํ์ ๋ง์ถฐ ๊ฐ์ฒด ์์ฑ
const laptop: Product = {
name: "MacBook Pro",
price: 2500000
};
// โ ์๋ฌ ๋ฐ์: Product ํํ์ ์๋ 'color'๋ฅผ ๋ฃ๊ฑฐ๋ ํ์
์ ํ๋ฆฌ๋ฉด ๊ฐ์งํจ
const phone: Product = {
name: "iPhone",
price: "150๋ง์", // Error: 'string'์ 'number' ํ์
์ ํ ๋นํ ์ ์์
color: "silver" // Error: 'Product' ํ์์ 'color'๊ฐ ์์
};
3.2.2 "๋ ํ์ดํ(Duck Typing)"๊ณผ ๊ตฌ์กฐ์ ํ์ดํ ๐ฆ
ํ์ ์คํฌ๋ฆฝํธ์ ํฅ๋ฏธ๋ก์ด ์ ์ '๊ตฌ์กฐ์ ํ์ดํ(Structural Typing)' ๋ฐฉ์์ ์ด๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ฆ์ด ๋ฌ๋ผ๋ ๋ด๋ถ ๊ตฌ์กฐ(Shape)๊ฐ ๊ฐ์ผ๋ฉด ๊ฐ์ ํ์ ์ผ๋ก ์ธ์ ํด ์ค๋๋ค.
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
// ๋ช
์์ ์ผ๋ก Point ์ธํฐํ์ด์ค๋ฅผ ์ฐ์ง ์์์ง๋ง, ํํ(Shape)๊ฐ ๊ฐ์ผ๋ฏ๋ก ํต๊ณผ!
const myObj = { x: 10, y: 20, z: 30 };
printPoint(myObj);
3.3 ์ ํ์ ์์ฑ(?)๊ณผ ์ฝ๊ธฐ ์ ์ฉ ์์ฑ(readonly) ๐
3.3.1 ์ ํ์ ์์ฑ (Optional Properties: ?) โ
์์ฑ ์ด๋ฆ ๋ค์ ๋ฌผ์ํ(?)๋ฅผ ๋ถ์ฌ์ ์ ์ํฉ๋๋ค. ํด๋น ์์ฑ์ด ๊ฐ์ฒด์ ์์ด๋ ๋๊ณ ์์ด๋ ๋ ๋ ์ฌ์ฉํฉ๋๋ค.
- ์ค๋ฌด ํ์ฉ: ํ์๊ฐ์ ์ ํ์ ์ ๋ณด(ID, ๋น๋ฐ๋ฒํธ)์ ์ ํ ์ ๋ณด(์๊ธฐ์๊ฐ, ์น์ฌ์ดํธ ์ฃผ์)๋ฅผ ๊ตฌ๋ถํ ๋ ์์ฃผ ์ฐ์ ๋๋ค.
- ํน์ง: ๊ฐ์ ๋ฃ์ง ์์ผ๋ฉด ์๋์ผ๋ก
undefined๊ฐ ํ ๋น๋ ๊ฒ์ฒ๋ผ ์ทจ๊ธ๋ฉ๋๋ค.
interface UserProfile {
id: string; // ํ์
nickname: string; // ํ์
bio?: string; // ์ ํ (์์ ์๋, ์์ ์๋ ์์)
website?: string; // ์ ํ
}
const user1: UserProfile = {
id: "user01",
nickname: "ํ๊ถ๋ธ์ด"
// bio์ website๊ฐ ์์ด๋ ์๋ฌ๊ฐ ๋์ง ์์ต๋๋ค.
};
3.3.2 ์ฝ๊ธฐ ์ ์ฉ ์์ฑ (Readonly Properties: readonly) ๐
์์ฑ ์ด๋ฆ ์์ readonly ํค์๋๋ฅผ ๋ถ์
๋๋ค. ๊ฐ์ฒด๊ฐ ์ฒ์ ์์ฑ๋ ๋๋ง ๊ฐ์ ํ ๋นํ ์ ์๊ณ , ๊ทธ ์ดํ์๋ ๊ฐ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
- ์ค๋ฌด ํ์ฉ: API ํค, ๊ณ ์ ID, ์ค์ ๊ฐ(Config) ๋ฑ ํ๋ก๊ทธ๋จ ์คํ ์ค์ ๋ฐ๋๋ฉด ์ ๋๋ ์ค์ํ ๋ฐ์ดํฐ๋ฅผ ๋ณดํธํ ๋ ์ฌ์ฉํฉ๋๋ค.
- ํน์ง: ๋ฐํ์์ด ์๋ ์ปดํ์ผ ๋จ๊ณ์์ ์๋ฌ๋ฅผ ์ก์์ค๋๋ค.
interface Config {
readonly apiKey: string;
readonly domain: string;
}
const myConfig: Config = {
apiKey: "ABC-12345",
domain: "https://example.com"
};
// โ ์๋ฌ ๋ฐ์: ์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ด๋ฏ๋ก ์์ ํ ์ ์์ต๋๋ค.
myConfig.apiKey = "XYZ-99999";
3.3.3 (์ฐธ์กฐ) ReadonlyArray\ ํ์ ๐
- ๋ฐฐ์ด ์ ์ฒด๋ฅผ ์์ ๋ถ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ณ ์ถ์ ๋๋
ReadonlyArray<number>๋ฅผ ์ฌ์ฉํฉ๋๋ค. push,pop๊ฐ์ ๋ฐฐ์ด ์์ ๋ฉ์๋๋ฅผ ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋ง์์ค๋๋ค.
const numbers: ReadonlyArray<number> = [1, 2, 3];
// โ ์๋ฌ ๋ฐ์: 'push'๊ฐ ์กด์ฌํ์ง ์์
numbers.push(4);
3.4 ๋์ ํค๋ฅผ ๋ค๋ฃจ๋ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ (Index Signature) ๐
์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ๋, ์์ฑ์ ์ด๋ฆ(Key)์ ๋ฏธ๋ฆฌ ์ ์ ์๊ฑฐ๋ ์์ฑ์ ๊ฐ์๊ฐ ์ ๋์ ์ผ ๋ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
3.4.1 ๊ธฐ๋ณธ ๋ฌธ๋ฒ ๐
๋๊ดํธ [] ์์ ํค์ ํ์
๊ณผ ๊ฐ์ ํ์
์ ์ ์ํฉ๋๋ค.
interface SalaryInfo {
// [key: ํคํ์
]: ๊ฐํ์
[role: string]: number;
}
const teamSalary: SalaryInfo = {
developer: 5000,
designer: 4500,
manager: 5500,
// ์ด๋ค ํค๋ฅผ ์ถ๊ฐํด๋ ๊ฐ์ด ์ซ์๋ผ๋ฉด ํต๊ณผ๋ฉ๋๋ค.
};
3.4.2 ์ค๋ฌด์์ ์ฌ์ฉํ๋ ์ด์ ๐ก
- ๋์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ: API ์๋ต์์ ํค ๊ฐ์ด ์ฌ์ฉ์ ID๋ ๋ ์ง์ฒ๋ผ ๊ณ์ ๋ณํ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ ํ์์ ์ ๋๋ค.
- ๊ฐ์ฒด๋ฅผ ์ฌ์ (Dictionary)์ฒ๋ผ ์ธ ๋: ํน์ ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ฐ์ดํฐ๋ฅผ ๋งคํํ ๋ ์ ์ฉํฉ๋๋ค.
interface ErrorMessages {
[code: string]: string;
}
const apiErrors: ErrorMessages = {
"404": "ํ์ด์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.",
"500": "์๋ฒ ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค.",
"403": "๊ถํ์ด ์์ต๋๋ค.",
};
3.4.3 ์ฃผ์์ฌํญ ๋ฐ ๊ท์น โ ๏ธ
- ํ์ ์์ฑ๊ณผ ํจ๊ป ์ฌ์ฉํ๊ธฐ: ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๊ฐ ์์ผ๋ฉด ๋ค๋ฅธ ๋ช
์์ ์์ฑ๋ ๊ทธ ๊ท์น์ ๋ฐ๋ผ์ผ ํฉ๋๋ค.
typescript interface UserInventory { [itemName: string]: number; gold: number; // โ ๊ฐ๋ฅ (์ธ๋ฑ์ค ์๊ทธ๋์ฒ์ ํ์ ์ผ์น) // username: string; // โ ์๋ฌ: ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๊ฐ ๋ชจ๋ ๊ฐ์ number๋ก ๊ท์ ํ๊ธฐ ๋๋ฌธ } - ์ฌ๋ฌ ํ์
ํ์ฉํ๊ธฐ: ๋ง์ฝ ๊ฐ์ ์ฌ๋ฌ ํ์
์ ๋ฃ๊ณ ์ถ๋ค๋ฉด ์ ๋์จ ํ์
์ ์ฌ์ฉํฉ๋๋ค.
typescript interface FlexibleConfig { [key: string]: string | number | boolean; version: number; // โ ์ด์ string | number | boolean ๋ฒ์ ์์ ์์ผ๋ฏ๋ก ๊ฐ๋ฅ } - ํค์ ํ์
: ์ธ๋ฑ์ค ์๊ทธ๋์ฒ์ ํค ํ์
์ ๋ณดํต
string,number,symbol๋ง ๊ฐ๋ฅํฉ๋๋ค.
3.4.4 (์ฐธ์กฐ) Record\ ์ ํธ๋ฆฌํฐ ํ์ ๐ ๏ธ
์ค๋ฌด์์๋ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ฅผ ์ง์ ์์ฑํ๋ ๋์ , ํ์
์คํฌ๋ฆฝํธ์์ ์ ๊ณตํ๋ Record๋ฅผ ์จ์ ๋ ๊ฐ๊ฒฐํ๊ฒ ํํํ๊ธฐ๋ ํฉ๋๋ค.
interface Obj { [key: string]: number; }type Obj = Record<string, number>;(์์ ๋์ผํ ์๋ฏธ)
3.5 Type Alias (ํ์ ๋ณ์นญ) ์ฌ์ฉ๋ฒ ๐ท๏ธ
ํ์ ๋ณ์นญ(Type Alias)์ ๋ง ๊ทธ๋๋ก ํน์ ํ์ ์ด๋ ์ธํฐํ์ด์ค์ ์๋ก์ด ์ด๋ฆ(๋ณ๋ช )์ ๋ถ์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
3.5.1 ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ ๐
๊ฐ์ฒด๋ฟ๋ง ์๋๋ผ ์ผ๋ฐ ๋ณ์ ํ์ , ์ ๋์จ ํ์ ๋ฑ ๋ชจ๋ ํ์ ์ ์ด๋ฆ์ ๋ถ์ผ ์ ์์ต๋๋ค.
// 1. ๊ธฐ๋ณธ ํ์
์ ๋ณ์นญ ๋ถ์ด๊ธฐ
type MyString = string;
const name: MyString = "Kim";
// 2. ๊ฐ์ฒด ํ์
์ ์ (Interface์ ์ ์ฌ)
type User = {
id: number;
name: string;
};
const worker: User = { id: 1, name: "Kim" };
3.5.2 Interface vs Type Alias ๐ค
์ค๋ฌด์์ interface ๋์ type์ ์ฐ๋ ๊ฒฐ์ ์ ์ธ ์ด์ ๋ ๋ฐ๋ก ์๋ ๊ธฐ๋ฅ๋ค ๋๋ฌธ์
๋๋ค.
3.5.2.1 ์ ๋์จ ํ์ (Union Types) ๐ฅ
"A ์ด๊ฑฐ๋ B์ด๋ค"๋ผ๋ ํ์ ์ ์ ์ํ ๋ ์ฌ์ฉํฉ๋๋ค. (Interface๋ ๋ถ๊ฐ๋ฅ)
type Status = "success" | "error" | "loading";
const currentStatus: Status = "success"; // โ
OK
const wrongStatus: Status = "pending"; // โ ์๋ฌ: ์ง์ ๋ 3๊ฐ ๋ฌธ์์ด ์ธ์ ํ์ฉ ์ ํจ
3.5.2.2 ํํ (Tuple) ๐ฆ
๋ฐฐ์ด์ ์์ ๊ฐ์์ ๊ฐ ์์์ ํ์ ์ ๊ณ ์ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
type Point = [number, number];
const coordinates: Point = [10, 20]; // โ
OK
3.5.2.3 ๊ต์ฐจ ํ์ (Intersection Types) โ
๋ ๊ฐ ์ด์์ ํ์
์ ํ๋๋ก ํฉ์น ๋ & ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
type Name = { name: string };
type Age = { age: number };
type Person = Name & Age; // { name: string, age: number } ์ ๊ฐ์
3.5.2.4 ๋ณต์กํ ํ์ ๊ด๋ฆฌ โ๏ธ
API ํธ์ถ ๊ฒฐ๊ณผ๋ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์ ์ํ ๋ ๋งค์ฐ ์ง๊ด์ ์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค.
type ResponseData = {
id: number;
content: string;
};
// ์ ๋์จ๊ณผ ๊ฐ์ฒด ํ์
์ ์กฐํฉํ ์ค๋ฌดํ ํจํด
type ApiResponse =
| { status: "success"; data: ResponseData }
| { status: "error"; message: string };
function handleResponse(response: ApiResponse) {
if (response.status === "success") {
console.log(response.data.content);
} else {
console.log(response.message);
}
}
3.5.3 (์ฐธ์กฐ) ์์(extends)? ๐ฒ
์ธํฐํ์ด์ค์์ ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก, ํด๋์ค์ ์์ ๊ฐ๋ ๊ณผ ๋น์ทํฉ๋๋ค.
- ๋ฐฉ์: ์๋ก์ด ์ธํฐํ์ด์ค๊ฐ ๊ธฐ์กด ์ธํฐํ์ด์ค์ ์์ฑ์ ๋ฌผ๋ ค๋ฐ์ต๋๋ค.
- ํน์ง (์๊ฒฉํจ): ๋ถ๋ชจ์ ์์ ๊ฐ์ ์์ฑ ํ์ ์ด ์ถฉ๋ํ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์์ผ ๋ฏธ๋ฆฌ ๋ฐฉ์งํฉ๋๋ค.
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// โ ์ถฉ๋ ๋ฐ์ ์ ์๋ฌ interface Cat extends Animal { name: number; // Error: 'Animal'์ 'name(string)'๊ณผ ํ์ ์ด ์ ๋ง์! }
3.5.4 ๋ฌด์์ ์จ์ผ ํ ๊น? ๐ค
- ๊ฐ์ฒด์ ๊ตฌ์กฐ๋ฅผ ์ ์ํ๊ณ ์์(extends)์ด ๋น๋ฒํ๋ค๋ฉด? โ
Interface - ์ ๋์จ(|), ๊ต์ฐจ(&), ๊ธฐ๋ณธ ํ์
๋ณ์นญ์ด ํ์ํ๋ค๋ฉด? โ
Type Alias
4. ํจ์ ๐
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
4.1. ํจ์ ํ์ ์ ์ โ๏ธ
4.1.1. ๊ธฐ๋ณธ์ ์ธ ํจ์ ํ์ ์ ์
๊ฐ์ฅ ๊ธฐ์ด์ ์ด๋ฉด์๋ ํ์์ ์ธ ํํ์ ๋๋ค. ์ธ์์ ๋ฐํ ํ์ (Return Type)์ ๋ช ์ํฉ๋๋ค.
function add(a: number, b: number): number {
return a + b;
}
// ํ์ดํ ํจ์ ๋ฐฉ์
const multiply = (a: number, b: number): number => a * b;
4.1.2. ์ ํ์ ๋งค๊ฐ๋ณ์์ ๊ธฐ๋ณธ๊ฐ (Optional & Default) โ๏ธ
ํจ์์ ํ๋ผ๋ฏธํฐ๋ ?๋ฅผ ์ฌ์ฉํด ์ ํ์ ์ผ๋ก ๋ฐ๊ฑฐ๋, ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ์ ์์ต๋๋ค.
function greet(name: string, greeting?: string): string {
return `${greeting || 'Hello'}, ${name}`;
}
console.log(greet("์ฒ ์")); // "Hello, ์ฒ ์"
console.log(greet("์ํฌ", "์๋
")); // "์๋
, ์ํฌ"
4.2. ํจ์ ํ์ ๋ณ์นญ (Function Type Alias) ๐ท๏ธ
ํจ์ ์์ฒด์ ํ์ ์ ๋ฏธ๋ฆฌ ์ ์ํด๋๊ณ ์ฌ์ฌ์ฉํ๋ ๋ฐฉ์์ ๋๋ค. ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ์ํ ๋ ์ค๋ฌด์์ ๋งค์ฐ ๋ง์ด ์ฐ์ ๋๋ค.
type Formatter = (text: string, uppercase: boolean) => string;
const myFormatter: Formatter = (str, isUpper) => {
return isUpper ? str.toUpperCase() : str.toLowerCase();
};
4.3. ํจ์ ์ค๋ฒ๋ก๋ฉ (Function Overloading) ๐
์ ๋ฌ๋ฐ๋ ์ธ์์ ํ์ ์ ๋ฐ๋ผ ๋ฐํ๋๋ ํ์ ์ด ๋ฌ๋ผ์ง ๋ ์ฌ์ฉํฉ๋๋ค. API ์๋ต ์ฒ๋ฆฌ๋ ์ ํธ๋ฆฌํฐ ํจ์๋ฅผ ๋ง๋ค ๋ ์ ์ฉํฉ๋๋ค.
// ์ ์ธ๋ถ: ์ด๋ค ์กฐํฉ์ด ๊ฐ๋ฅํ์ง ์ ์
function getValue(v: string): string;
function getValue(v: number): number;
// ๊ตฌํ๋ถ: ์ค์ ๋ก์ง (any ๋๋ ์ ๋์จ ํ์
์ฌ์ฉ)
function getValue(v: any): any {
return v;
}
const str = getValue("ABC"); // ํ์
์ด string์ผ๋ก ์ถ๋ก ๋จ
const num = getValue(123); // ํ์
์ด number๋ก ์ถ๋ก ๋จ
4.4. ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถํด ํ ๋น (Destructuring) ๐ฆ
React ์ปดํฌ๋ํธ์ Props๋ ๋ณต์กํ ์ต์ ๊ฐ์ฒด๋ฅผ ๋ฐ์ ๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ํจํด์ ๋๋ค.
interface UserConfig {
id: string;
isAdmin: boolean;
}
// ์ธ์ ๋จ๊ณ์์ ํ์
์ ๋ฐ๋ก ์ ์ํ๊ฑฐ๋ interface๋ฅผ ํ์ฉ
function loginUser({ id, isAdmin }: UserConfig): void {
console.log(`ID: ${id}, Admin: ${isAdmin}`);
}
4.4.1. ์ ์ด๋ ๊ฒ ์ฐ๋์? (Before vs After) ๐ค
๊ตฌ์กฐ ๋ถํด ํ ๋น์ ์ ์ฐ๋ฉด ๋งค๋ฒ user.id, user.isAdmin์ฒ๋ผ ๊ฐ์ฒด๋ช
์ ๋ฐ๋ณตํด์ ์จ์ผ ํฉ๋๋ค.
// ๊ตฌ์กฐ ๋ถํด ํ ๋น ๋ฏธ์ฌ์ฉ
function loginUser(user: UserConfig) {
console.log(user.id); // ๋งค๋ฒ user. ๋ฅผ ๋ถ์ฌ์ผ ํจ
console.log(user.isAdmin);
}
// ๊ตฌ์กฐ ๋ถํด ํ ๋น ์ฌ์ฉ
function loginUser({ id, isAdmin }: UserConfig) {
console.log(id); // ๋ฐ๋ก ๋ณ์์ฒ๋ผ ์ฌ์ฉ ๊ฐ๋ฅ!
console.log(isAdmin);
}
4.4.2. ๋ฌธ๋ฒ ์์ธ ๋ถ์ ๐
({ id, isAdmin }: UserConfig)๋ฅผ ์ชผ๊ฐ๋ณด๋ฉด ์ด๋ ์ต๋๋ค.
{ id, isAdmin }: "์ธ์๋ก ๊ฐ์ฒด๊ฐ ๋ค์ด์ฌ ํ ๋ฐ, ๊ทธ ์์ id ์์ฑ๊ณผ isAdmin ์์ฑ์ ์ฐพ์์ ๊ฐ์ ์ด๋ฆ์ ๋ณ์๋ก ๋ง๋ค์ด์ค!"๋ผ๋ ๋ช ๋ น์ ๋๋ค.: UserConfig: "๊ทธ๋ฐ๋ฐ ๊ทธ ๊ฐ์ฒด๋ UserConfig๋ผ๋ ํ์ ๊ท๊ฒฉ์ ์ง์ผ์ผ ํด!"๋ผ๋ ํ์ ์ ์์ ๋๋ค.
4.5. ํ์ดํ ํจ์ ๐น
4.5.1. ํ์ดํ ํจ์ (Arrow Functions)
ํ์ ์คํฌ๋ฆฝํธ์์ ํ์ดํ ํจ์๋ ํ์ ์ ์ ์ํ๋ ๋ฐฉ์์ด ๋ ๊ฐ์ง์ ๋๋ค.
4.5.1.1. ํจ์ ์ ์ธ๊ณผ ๋์์ ํ์ ์ ์ (๊ฐ์ฅ ์ผ๋ฐ์ )
const add = (a: number, b: number): number => a + b;
4.5.1.2. ๋ณ์์ ํจ์ ํ์ ์ ๋ฏธ๋ฆฌ ์ง์ (์ถ์ฒ!) โจ
type CalculateFn = (a: number, b: number) => number;
const multiply: CalculateFn = (a, b) => a * b; // ์ธ์์ ํ์
์ ์๋ตํด๋ ์๋์ผ๋ก ์ถ๋ก ๋จ
4.6. Rest ํ๋ผ๋ฏธํฐ (๋๋จธ์ง ๋งค๊ฐ๋ณ์) ๐๏ธ
4.6.1. ์ธ์์ ๊ฐ์๊ฐ ์ ํด์ง์ง ์์์ ๋ ์ฌ์ฉํฉ๋๋ค.
ํ์ ์คํฌ๋ฆฝํธ์์๋ Rest ํ๋ผ๋ฏธํฐ๊ฐ ๋ฐ๋์ ๋ฐฐ์ด ํ์ ์ด์ด์ผ ํ๋ค๋ ์ ์ด ํต์ฌ์ ๋๋ค.
// ...numbers: number[] ๋ ์ธ์(๋งค๊ฐ๋ณ์)๋ก ์ซ์๋ค๋ง ๋ค์ด์๋ ๋ฐฐ์ด์ ๋ฐ๊ฒ ๋ค.
// : number ๋ ์ด ํจ์๋ ๊ณ์ฐ์ ๋๋ด๊ณ ๊ฒฐ๊ณผ๋ฌผ๋ก ์ซ์(number) ํ๋๋ฅผ ๋๋ ค์ฃผ๊ฒ ๋ค!
function sum(...numbers: number[]): number {
return numbers.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100
4.6.2. API ๋ก๊ฑฐ (Rest + Destructuring) ๐ชต
ํน์ ๊ณ ์ ์ธ์์ ๋๋จธ์ง ์ต์ ๋ค์ ๋ฌถ์ด์ ์ฒ๋ฆฌํ ๋ ์ด ๋ ๊ฐ๋ ์ ๊ฒฐํฉ
interface LogOptions {
level: 'info' | 'error' | 'warn';
silent?: boolean;
}
// ์ฒซ ๋ฒ์งธ ์ธ์๋ message, ๋๋จธ์ง๋ ์ฌ๋ฌ ๊ฐ์ ์ต์
๊ฐ์ฒด๋ค์ ๋ฐฐ์ด๋ก ๋ฐ์
const logMessage = (message: string, ...options: LogOptions[]) => {
console.log(`[Message]: ${message}`);
console.log(`[Options]:`, options);
};
logMessage(
"์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต",
{ level: 'info' },
{ level: 'warn', silent: true }
);
4.7. ์ฝ๋ฐฑ(Callback) ํจ์์ ํ์ ์๊ทธ๋์ฒ ์ ์ ๐
์ฝ๋ฐฑ ํจ์๋ ๋ค๋ฅธ ํจ์์ ์ธ์๋ก ์ ๋ฌ๋๋ ํจ์๋ฅผ ๋งํ์ฃ . ํ์ ์คํฌ๋ฆฝํธ์์๋ ์ด ์ฝ๋ฐฑ ํจ์๊ฐ "์ด๋ค ์ธ์๋ฅผ ๋ฐ๊ณ , ๋ฌด์์ ๋ฐํํ๋์ง" ๋ฏธ๋ฆฌ ๊ท๊ฒฉ(์๊ทธ๋์ฒ)์ ์ ํด๋ ์ ์์ต๋๋ค.
4.7.1. ๊ธฐ๋ณธ ์ ์ ๋ฐฉ์ (์ธ๋ผ์ธ)
function processUserInput(name: string, callback: (n: string) => void) {
// 1. name์ ์ฒ๋ฆฌํ๊ณ
console.log(`์ฌ์ฉ์ ์ด๋ฆ: ${name}`);
// 2. ์ฒ๋ฆฌ๊ฐ ๋๋๋ฉด ์ฝ๋ฐฑ ํจ์๋ฅผ ์คํ
callback(name);
}
processUserInput("์ฒ ์", (userName) => {
console.log(`${userName}๋, ํ์ํฉ๋๋ค!`);
});
4.7.2. ๋ณ์นญ(Type Alias) ์ฌ์ฉ ๋ฐฉ์ (์ค๋ฌด ๊ถ์ฅ) ๐ก
์ค๋ฌด์์๋ ์ฝ๋ฐฑ ํ์ ์ด ๋ณต์กํด์ง๋ ๊ฒฝ์ฐ๊ฐ ๋ง์, ๋ฐ๋ก ์ด๋ฆ์ ๋ถ์ฌ ์ ์ํ๋ ๋ฐฉ์์ ํจ์ฌ ์ ํธํฉ๋๋ค.
// ์ฝ๋ฐฑ ํ์
์ ์ (์ค๊ณ๋)
type Checker = (id: string, info: { role: string }) => boolean;
// 2. ์คํ ํจ์: ๋ด๋ถ์์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฝ๋ฐฑ์ ๋์ ธ์ค
const run = (id: string, callback: Checker) => {
const isOk = callback(id, { role: 'admin' }); // ๊ฐ์ฒด ์ ๋ฌ!
console.log(isOk ? "์น์ธ" : "๊ฑฐ๋ถ");
};
// 3. ์ค์ ์ฌ์ฉ: ๋์ ธ์ค ๊ฐ์ฒด(info)๋ฅผ ๊บผ๋ด์ ๋ก์ง ์ง๊ธฐ
run("user01", (id, info) => {
return info.role === 'admin'; // admin์ด๋ฉด true ๋ฐํ
});
4.7.3. ์ฝ๋ฐฑ์ด ์ ํ ์ฌํญ์ผ ๋ (?) โ
์ฝ๋ฐฑ ํจ์๋ฅผ ์ค ๋๋ ์๊ณ ์ ์ค ๋๋ ์๋ค๋ฉด ?๋ฅผ ๋ถ์
๋๋ค. ์ด๋ ํจ์ ๋ด๋ถ์์ && ์ฐ์ฐ์๋ ์กฐ๊ฑด๋ฌธ์ ์จ์ ์์ ํ๊ฒ ํธ์ถํ๋ ๊ฒ ๊ตญ๋ฃฐ์
๋๋ค.
function fetchData(url: string, onSuccess?: (data: any) => void) {
// ... ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง ...
const data = { id: 1, content: "Hello" };
// onSuccess๊ฐ ์์ ๋๋ง ์คํํด๋ผ! (&& ์ฐ์ฐ์ ํ์ฉ)
onSuccess && onSuccess(data);
}
4.7.4. ๊ฐ๋ณ ์ธ์(...args)๋ฅผ ๋ฐฐ์ด ํ์ ์ผ๋ก ๋ฌถ์ด ์ฒ๋ฆฌํ๊ธฐ ๐๏ธ
// ...tags ๋ค์ : string[] ์ "๋ฌธ์์ด๋ค๋ง ๋ชจ์ธ ๋ฐฐ์ด"์ด๋ผ๋ ๋ป
// ๋ฐ๋์ number[], string[] ์ฒ๋ผ ๋ฐฐ์ด ํํ๋ก ์จ์ผ ํฉ๋๋ค
// ๋ฌด์กฐ๊ฑด ๋งค๊ฐ๋ณ์์ ๋งจ ๋ง์ง๋ง์ ๋ฑ ํ ๋ฒ๋ง ์ธ ์ ์์ต๋๋ค
function makeHashTags(...tags: string[]): string {
// ํจ์ ๋ด๋ถ์์๋ map, filter, reduce ๊ฐ์ ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ๋ฐ๋ก ์ธ ์ ์์ด ํธํฉ๋๋ค
return tags.map(t => `#${t}`).join(' ');
}
// 1๊ฐ๋ฅผ ๋ฃ๋ 3๊ฐ๋ฅผ ๋ฃ๋ 'tags'๋ผ๋ ๋ฐฐ์ด๋ก ์ฒ๋ฆฌ๋จ
console.log(makeHashTags("ํ์
์คํฌ๋ฆฝํธ")); // "#ํ์
์คํฌ๋ฆฝํธ"
console.log(makeHashTags("JS", "TS", "React")); // "#JS #TS #React"
5. ํด๋์ค(Class)์ ๊ฐ์ฒด ์งํฅ ๐๏ธ
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
ํ์ ์คํฌ๋ฆฝํธ ํด๋์ค๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ํด๋์ค ๋ฌธ๋ฒ์ ํ์ ์ ์์ ์ ๊ทผ ์ ์ด์๊ฐ ์ถ๊ฐ๋ ํํ์ ๋๋ค.
5.1 ํด๋์ค ์ฌ์ฉ ์ ํต์ฌ ์ฒดํฌ๋ฆฌ์คํธ โ
- **
newํค์๋**: ํด๋์ค๋ ์ค๊ณ๋์ผ ๋ฟ์ด๋ฏ๋ก, ๋ฐ๋์new ํด๋์ค๋ช ()์ผ๋ก ๊ฐ์ฒด(์ธ์คํด์ค)๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํด์ผ ํฉ๋๋ค. - **
this์ฌ์ฉ**: ํด๋์ค ๋ด๋ถ์ ๋ณ์๋ ๋ฉ์๋์ ์ ๊ทผํ ๋๋ ๋ฐ๋์this.์ ๋ถ์ฌ์ผ ํฉ๋๋ค. - ** ์ด๊ธฐํ ํ์**: ์ ์ธ๋ง ํ๊ณ ๊ฐ์ ํ ๋นํ์ง ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ฉ๋๋ค. (๋๋
name!: string์ฒ๋ผ ํ์ ๊ธฐํธ๋ฅผ ์จ์ผ ํจ)
5.1.1 ์ ์์ ์ธ ์ ์ธ ๋ฐฉ๋ฒ ๐
class Robot {
// 1. ๋ฉค๋ฒ ๋ณ์ ํ์
์ ์ธ
name: string;
model: string;
// 2. ์์ฑ์(Constructor) ์ ์
constructor(name: string, model: string) {
this.name = name;
this.model = model;
}
// 3. ๋ฉ์๋ ์ ์
move(): void {
console.log(`${this.name}(${this.model})์ด ์์ง์
๋๋ค. ๐ค`);
}
}
// ์ฌ์ฉ ๋ฐฉ๋ฒ (์ธ์คํด์ค ์์ฑ)
const myRobot = new Robot("ํ๊ถV", "V1");
myRobot.move(); // "ํ๊ถV(V1)์ด ์์ง์
๋๋ค."
5.1.2 ์ค๋ฌดํ ๋จ์ถ ์ ์ธ โก
์ค๋ฌด์์๋ ์ ๋ฐฉ์์ด ๋ฒ๊ฑฐ๋ก์ ์๋์ฒ๋ผ ์์ฑ์ ๋งค๊ฐ๋ณ์์ ์ ๊ทผ ์ ์ด์(public, private ๋ฑ)๋ฅผ ์ง์ ๋ถ์ฌ์ ๋ณ์ ์ ์ธ๊ณผ ํ ๋น์ ํ ๋ฒ์ ๋๋
๋๋ค.
class User {
// ์์ฑ์์ ์ ๊ทผ ์ ์ด์๋ฅผ ๋ถ์ด๋ฉด ๋ฉค๋ฒ ๋ณ์ ์ ์ธ + ํ ๋น์ด ์๋์ผ๋ก ๋จ!
constructor(public nickname: string, private email: string) {}
showInfo() {
console.log(`์ด๋ฆ: ${this.nickname}, ์ด๋ฉ์ผ: ${this.email} ๐ค`);
}
}
const user = new User("๊ฟํ๋ฌ", "tip@example.com");
console.log(user.nickname); // โ
OK (public)
// console.log(user.email); // โ ์๋ฌ! (private์ด๋ผ ์ธ๋ถ ์ ๊ทผ ๋ถ๊ฐ)
5.2 ์ ๊ทผ ์ ์ด์ 3์ข ์ธํธ ๐
| ์ ์ด์ | ํน์ง | ์ค๋ช |
|---|---|---|
public |
๊ณต๊ฐ | ์ด๋์๋ ์ ๊ทผ ๊ฐ๋ฅ (๊ธฐ๋ณธ๊ฐ) |
private |
๋น๊ณต๊ฐ | ํด๋น ํด๋์ค ๋ด๋ถ์์๋ง ์ ๊ทผ ๊ฐ๋ฅ (์ธ๋ถ/์์ ๋ถ๊ฐ) |
protected |
๋ณดํธ | ํด๋์ค ๋ด๋ถ + ์์๋ฐ์ ์์๊น์ง๋ ์ ๊ทผ ๊ฐ๋ฅ |
class Employee {
public name: string; // ๋๊ตฌ๋ ๋ณผ ์ ์์
private salary: number; // ๊ธ์ฌ๋ ๋ณธ์ธ๋ง(ํด๋์ค ๋ด๋ถ) ์ ์ ์์
protected department: string; // ๋ถ์ ์ ๋ณด๋ ์์ ํด๋์ค๊น์ง๋ง ๊ณต์
constructor(name: string, salary: number, department: string) {
this.name = name;
this.salary = salary;
this.department = department;
}
public getSalaryInfo() {
return `${this.name}์ ๊ธ์ฌ๋ ๋น๋ฐ์
๋๋ค. ๐คซ`; // ๋ด๋ถ์์๋ salary ์ ๊ทผ ๊ฐ๋ฅ
}
}
class Manager extends Employee {
public changeDept(newDept: string) {
this.department = newDept; // โ
protected๋ผ์ ์์์ ์ ๊ทผ ๊ฐ๋ฅ!
// this.salary = 0; // โ ์๋ฌ! private์ ์์๋ ์ ๊ทผ ๋ถ๊ฐ
}
}
const worker = new Employee("๊น์ฒ ์", 5000, "๊ฐ๋ฐํ");
console.log(worker.name); // โ
OK
// console.log(worker.salary); // โ ์๋ฌ! (์ธ๋ถ ์ ๊ทผ ๋ถ๊ฐ)
5.3 private vs JS์ # (๋ฌด์จ ์ฐจ์ด?) ๐ค
๋ ๋ค ์ธ๋ถ ์ ๊ทผ์ ๋ง์ง๋ง ๊ฒฐ์ ์ ์ธ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
- 5.3.1
private(TS ๋ฌธ๋ฒ):- ์ปดํ์ผ ๋จ๊ณ์์ ์๋ฌ๋ฅผ ์ก์์ค๋๋ค.
- ์ค์ JS๋ก ๋ณํ๋๋ฉด ์ผ๋ฐ ๋ณ์์ ๋๊ฐ์ด ๋ณด์ ๋๋ค (๋ฐํ์ ๊ฐ์ ๋ ฅ์ ์์).
- 5.3.2
#(JS ํ์ค ๋ฌธ๋ฒ):- ๋ฐํ์(์คํ ์์ )์์๋ ์์ ํ ์จ๊ฒจ์ง๋๋ค.
- ๋ธ๋ผ์ฐ์ ์์ฒด์์ ์์ ์ ๊ทผ์ ๋ชป ํ๊ฒ ๋ง์๋ฒ๋ฆฝ๋๋ค.
5.4 ์ถ์ ํด๋์ค (Abstract Class) ๐งฑ
์ถ์ ํด๋์ค๋ ํ๋ง๋๋ก '๋ฏธ์์ฑ ์ค๊ณ๋'์ ๋๋ค. ์ค์ค๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์๋ ์์ง๋ง, ์์ ํด๋์ค๋ค์ด ๋ฐ๋์ ๊ฐ์ ธ์ผ ํ ๊ณตํต ๊ธฐ๋ฅ์ ๋ฌผ๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
5.4.1 abstract ํค์๋๋ฅผ ์ด์ฉํ ๊ณตํต ๋ผ๋ ๊ตฌ์ถ
์ถ์ ํด๋์ค ์์๋ ์ผ๋ฐ ๋ฉ์๋(๊ตฌํ ์๋ฃ)์ ์ถ์ ๋ฉ์๋(์ด๋ฆ๋ง ์ ์)๋ฅผ ์์ด์ ๋ฃ์ ์ ์์ต๋๋ค.
abstract class Animal {
// 1. ๊ณตํต ๊ธฐ๋ฅ (๊ตฌํ ์๋ฃ): ์์๋ค์ด ๊ทธ๋๋ก ์ฌ์ฉ
breath() {
console.log("์จ์ ์ฝ๋๋ค. ๐จ");
}
// 2. ์ถ์ ๋ฉ์๋ (๋ผ๋๋ง): ์์์ด "๋ฐ๋์" ์ง์ ๊ตฌํํด์ผ ํจ
abstract makeSound(): void;
}
class Dog extends Animal {
// abstract ๋ฉ์๋๋ฅผ ๊ตฌํ ์ ํ๋ฉด ์๋ฌ ๋ฐ์!
makeSound() {
console.log("๋ฉ๋ฉ! ๐ถ");
}
}
const myDog = new Dog();
myDog.breath(); // "์จ์ ์ฝ๋๋ค." (๋ถ๋ชจ๊บผ ์ฌ์ฉ)
myDog.makeSound(); // "๋ฉ๋ฉ!" (๋ณธ์ธ์ด ๊ตฌํํ ๊ฒ ์ฌ์ฉ)
// const animal = new Animal(); // โ ์๋ฌ! ์ถ์ ํด๋์ค๋ ์ง์ ๊ฐ์ฒด ์์ฑ ๋ถ๊ฐ
5.4.2 ์ธํฐํ์ด์ค ๊ตฌํ(implements)๊ณผ์ ์ญํ ์ฐจ์ด
| ๊ตฌ๋ถ | ์ถ์ ํด๋์ค (extends) |
์ธํฐํ์ด์ค (implements) |
|---|---|---|
| ์ญํ | ๊ธฐ๋ณธ ๋ฒ ์ด์ค ๋ฌผ๋ ค์ฃผ๊ธฐ (์์) | ๊ท๊ฒฉ/ํ์ ๋ง์ถ๊ธฐ (์ฅ์ฐฉ) |
| ๊ตฌํ๋ถ | ๋ฉ์๋์ ์ค์ ์ฝ๋ ํฌํจ ๊ฐ๋ฅ | ์ฝ๋ ํฌํจ ๋ถ๊ฐ (์ ์ธ๋ง ํจ) |
| ๋ชฉ์ | "๋๋ ๋ด ์์์ด๋ ๊ณตํต ๊ธฐ๋ฅ์ ์จ๋ผ" | "๋๋ ์ด ๊ธฐ๋ฅ(๋ฉ์๋)์ ๋ฐ๋์ ๊ฐ์ ธ๋ผ" |
| ๋ค์ค ์ฌ์ฉ | ๋จ ํ๋๋ง ์์ ๊ฐ๋ฅ | ์ฌ๋ฌ ๊ฐ ๋์์ ๊ตฌํ ๊ฐ๋ฅ |
6. ๊ณ ๊ธ ํ์ (Advanced Types) ๐
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
6.1. ์ ๋์ธ ํ์
(Union, |) ๐
- "A ๋๋ B"๋ผ๋ ๋ป์ ๋๋ค. ์ฌ๋ฌ ํ์ ์ค ํ๋์ผ ์ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
- API ์๋ต์ด๋ ์ํ๊ฐ์ ์ฒ๋ฆฌํ ๋ ์ฃผ๋ก ํ์ฉ๋ฉ๋๋ค.
// string์ด๊ฑฐ๋ number์ผ ์ ์์
let id: string | number;
id = "user_01"; // โ
OK
id = 123; // โ
OK
// ์ค๋ฌด ์์: ๋ก๋ฉ ์ํ ์ฒ๋ฆฌ
type Status = "success" | "error" | "loading";
function printStatus(status: Status) {
console.log(`ํ์ฌ ์ํ๋ ${status}์
๋๋ค.`);
}
printStatus("success"); // โ
OK
// printStatus("pending"); // โ ์๋ฌ! (์ ํด์ง ๋ฌธ์์ด ์ธ์๋ ๊ฑฐ๋ถ)
6.2. ์ธํฐ์น์
ํ์
(Intersection, &) ๐ค
- "A ๊ทธ๋ฆฌ๊ณ B"๋ผ๋ ๋ป์ ๋๋ค. ์ฌ๋ฌ ํ์ ์ ํ๋๋ก ํฉ์ณ์ ๋ชจ๋ ์์ฑ์ ๋ค ๊ฐ์ง๊ฒ ๋ง๋ญ๋๋ค.
- ์ ์ ์ ๋ณด์ ๊ถํ ์ ๋ณด๋ฅผ ํฉ์น ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
interface Person {
name: string;
}
interface Worker {
employeeId: number;
}
// Person๊ณผ Worker์ ๋ชจ๋ ์์ฑ์ ๊ฐ์ ธ์ผ ํจ
type Employee = Person & Worker;
const newEmployee: Employee = {
name: "๋ฐ๋๋ฆฌ",
employeeId: 9901
};
6.3. ํ์ ์ถ๋ก ๊ณผ ๋จ์ธ ๐
6.3.1. ํ์ ์ถ๋ก (Type Inference) โจ
- ๋ณ์๋ฅผ ์ ์ธํ๊ณ ๋ฐ๋ก ๊ฐ์ ํ ๋นํ๋ฉด ํ์ ์คํฌ๋ฆฝํธ๊ฐ ๊ทธ ๊ฐ์ ๋ณด๊ณ ํ์ ์ ์๋์ผ๋ก ์ ํฉ๋๋ค.
- ๋ช ํํ ๊ฒฝ์ฐ์๋ ์ถ๋ก ์ ๋งก๊ธฐ๋ ๊ฒ์ด ์ฝ๋๊ฐ ๊น๋ํฉ๋๋ค.
let name = "์ฒ ์"; // string์ผ๋ก ์๋ ์ถ๋ก
let age = 25; // number๋ก ์๋ ์ถ๋ก
// name = 123; // โ ์๋ฌ! ์ด๋ฏธ string์ผ๋ก ์ถ๋ก ๋๊ธฐ ๋๋ฌธ
6.3.2. ํ์
๋จ์ธ (Type Assertion, as) ๐ ๏ธ
- ๊ฐ๋ฐ์๊ฐ ํด๋น ํ์ ์ ๋ํด ๋ ํ์คํ ์๊ณ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
- ํค์๋:
as(๊ฐ์ฅ ๊ถ์ฅ๋๋ ๋ฐฉ์) - โ ๏ธ ์ค์ ๋ก ํ์ ์ด ๋ค๋ฅด๋ฉด ๋ฐํ์์ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ ์ฃผ์ํด์ผ ํฉ๋๋ค.
6.3.2.1. ๋จ์ธ์ผ๋ก ๊ตฌ์ฒด์ ์ธ ํ๊ทธ ์ง์ ํ๊ธฐ ๐ท๏ธ
document.querySelector๋ ๊ธฐ๋ณธ์ ์ผ๋ก Element๋ผ๋ ๋์ ๋ฒ์๋ฅผ ๋ฐํํฉ๋๋ค. ํน์ ํ๊ทธ์ ์์ฑ(์: input์ value, img์ src)์ ์ฐ๋ ค๋ฉด as๋ก ํ์
์ ์ขํ์ผ ํฉ๋๋ค.
// TS๋ ์ด๊ฒ ๊ทธ๋ฅ Element์ธ์ค ์์ง๋ง, ๊ฐ๋ฐ์๋ input ํ๊ทธ์ธ ๊ฑธ ์๋๋ค.
const myInput = document.getElementById("user-id") as HTMLInputElement;
// ๋จ์ธ ๋๋ถ์ value ์์ฑ์ ์ ๊ทผ ๊ฐ๋ฅํด์ง
console.log(myInput.value);
6.3.2.2. null ์ฒดํฌ ํจํด (์์ ํ ์ ๊ทผ) ๐ก๏ธ
์์๊ฐ ํ๋ฉด์ ์์ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด์ผ ํฉ๋๋ค. ์ค๋ฌด์์๋ Optional Chaining(?.)์ด๋ ์กฐ๊ฑด๋ฌธ์ ํ์๋ก ์ฌ์ฉํฉ๋๋ค.
const button = document.querySelector('.submit-btn') as HTMLButtonElement;
// ํจํด A: Optional Chaining (๊ถ์ฅ)
button?.click();
// ํจํด B: ์กฐ๊ฑด๋ฌธ (๋ณต์กํ ๋ก์ง์ผ ๋)
if (button) {
button.disabled = true;
button.innerText = "์ ์ก ์ค...";
}
6.3.2.3. ์ด๋ฒคํธ ๋ฆฌ์ค๋์ e.target ์ฒ๋ฆฌ ๐ฏ
์ด๋ฒคํธ ํจ์ ์์์ e.target์ ์ธ ๋๋ ํ์
๋จ์ธ์ด ํ์ํฉ๋๋ค. target์ ์ด๋ค ์์์ผ์ง TS๊ฐ ํ์ ํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
const handleInput = (e: Event) => {
// e.target์ ํ์ํ ํ์
์ผ๋ก ๋จ์ธํ์ฌ ์ฌ์ฉ
const target = e.target as HTMLInputElement;
console.log(target.value);
};
document.querySelector('#search')?.addEventListener('input', handleInput);
6.3.2.4. ์์ฃผ ์ฐ์ด๋ HTML ํ์ ๋ชฉ๋ก ๐
HTMLInputElement(input)HTMLButtonElement(button)HTMLAnchorElement(a ํ๊ทธ)HTMLImageElement(img ํ๊ทธ)HTMLFormElement(form ํ๊ทธ)
6.4. ํ์ ๊ฐ๋ (Type Guards) ๐ฎโโ๏ธ
ํ์ ๊ฐ๋๋ ๋ง ๊ทธ๋๋ก "ํ์ ์ ์งํค๋ ํ์๊พผ"์ ๋๋ค. ์ ๋์ธ ํ์ ์ฒ๋ผ ์ฌ๋ฌ ํ์ ์ด ์์ฌ ์์ ๋, ๋ฐํ์์์ ํ์ ์ ํ๋๋ก ํ์ ์ง์ด ์์ ํ๊ฒ ์ฝ๋๋ฅผ ์งค ์ ์๊ฒ ํด์ค๋๋ค.
6.4.1. typeof: ์์ ํ์
๋ถ๊ธฐ ๐
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก string, number, boolean ๊ฐ์ ๊ธฐ๋ณธ ํ์
์ ๊ตฌ๋ณํ ๋ ์๋๋ค.
function printId(id: string | number) {
if (typeof id === "string") {
// ์ด ์์์ id๋ 100% string์
๋๋ค.
console.log(id.toUpperCase());
} else {
// ์ฌ๊ธฐ์๋ ์๋์ผ๋ก number๊ฐ ๋ฉ๋๋ค.
console.log(id.toFixed(2));
}
}
6.4.2. instanceof: ํด๋์ค ๊ฐ์ฒด ๋ถ๊ธฐ ๐๏ธ
์ด๋ค ๊ฐ์ฒด๊ฐ ํน์ ํด๋์ค๋ก๋ถํฐ ๋ง๋ค์ด์ก๋์ง ํ์ธํ ๋ ์๋๋ค.
class Dog { bark() { console.log("๋ฉ๋ฉ"); } }
class Cat { meow() { console.log("์ผ์น"); } }
function speak(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark(); // Dog ํ์
์ผ๋ก ํ์
} else {
animal.meow(); // Cat ํ์
์ผ๋ก ํ์
}
}
6.4.3. ์ฌ์ฉ์ ์ ์ ํ์
๊ฐ๋ (is ํค์๋) ๐ค
๋ณต์กํ ๊ฐ์ฒด์ ํ์
์ ํ๋ณํ๋ ๋ณ๋์ ํจ์๋ฅผ ๋ง๋ค ๋ ์ฌ์ฉํ๋ฉฐ, ๋ฐํ ํ์
์ ์ธ์ is ํ์
์ ์ ์ด์ฃผ๋ ๊ฒ์ด ํต์ฌ์
๋๋ค.
interface User { name: string; role: string; }
interface Guest { name: string; }
// "person์ด User ํ์
์ธ์ง ํ์ธํ๋ ํจ์" ์ ์
function isUser(person: User | Guest): person is User {
return (person as User).role !== undefined;
}
function welcome(person: User | Guest) {
if (isUser(person)) {
// ์ด ๋ธ๋ก ์์์ person์ User ํ์
์ผ๋ก ๋์ ๋ฐ์ต๋๋ค.
console.log(`๊ด๋ฆฌ์ ${person.name}๋ ํ์ํฉ๋๋ค.`);
} else {
console.log(`๋ฐฉ๋ฌธ์ ${person.name}๋ ํ์ํฉ๋๋ค.`);
}
}
// ์ค์ ์์ ํธ์ถ
const admin = { name: "๊ฐํ์ฅ", role: "ADMIN" };
const guest = { name: "์ต๋ช
" };
welcome(admin); // ์ถ๋ ฅ: "๊ด๋ฆฌ์ ๊ฐํ์ฅ๋ ํ์ํฉ๋๋ค."
welcome(guest); // ์ถ๋ ฅ: "๋ฐฉ๋ฌธ์ ์ต๋ช
๋ ํ์ํฉ๋๋ค."
// ๋ฐฐ์ด์ ํ์ฉํ ๋ฐ๋ณต ์ฒ๋ฆฌ
const people: (User | Guest)[] = [
{ name: "์ด๋๋ฆฌ", role: "EDITOR" },
{ name: "๊ธธ๋" }
];
people.forEach(p => welcome(p));
7. ์ ๋ค๋ฆญ (Generics) ๐ฆ
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
7.1. ์ ๋ค๋ฆญ์ ๊ฐ๋ ๐ก
์ ๋ค๋ฆญ(Generics)์ ํ๋ง๋๋ก ํ์ ์ ๋ณ์์ฒ๋ผ ์ฌ์ฉํ๋ 'ํ์ ํ๋ผ๋ฏธํฐ' ๊ฐ๋ ์ ๋๋ค. ํจ์๋ ํด๋์ค๋ฅผ ๋ง๋ค ๋ ํ์ ์ ๋ฏธ๋ฆฌ ์ ํ์ง ์๊ณ , ์ฌ์ฉํ๋ ์์ ์ ํ์ ์ ๋๊ฒจ์ฃผ์ด ์ฌ์ฌ์ฉ์ฑ์ ๊ทน๋ํํ๋ ๊ฒ์ด ํต์ฌ์ ๋๋ค.
7.1.1. ์ ๋ค๋ฆญ์ด ์ ํ์ํ๊ฐ์? ๐ค
- [๋ฐฉ๋ฒ 1] ํ์
๋ณ๋ก ํจ์๋ฅผ ๋ค ๋ง๋ ๋ค (๋นํจ์จ) ๐ญ
typescript function echoNumber(item: number): number { return item; } function echoString(item: string): string { return item; } // ํ์ ์ด ๋์ด๋ ๋๋ง๋ค ํจ์๋ฅผ ๊ณ์ ๋ณต์ฌํด์ผ ํจ... - [๋ฐฉ๋ฒ 2] any ํ์
์ ์ด๋ค (์ํ) โ
typescript function echoAny(item: any): any { return item; } const result = echoAny(123); // result์ ํ์ ์ด any๊ฐ ๋์ด๋ฒ๋ฆผ. ์ซ์์ธ์ง ๋ฌธ์์ด์ธ์ง ์ถ์ ์ด ์ ๋จ -
[๋ฐฉ๋ฒ 3] ์ ๋ค๋ฆญ์ ์ด๋ค โ ```typescript // ๋ "์ด๋ค ํ์ ์ด๋ ๋ค์ด์ฌ ์ ์๋ ๋น ๊ณต๊ฐ"์ด๋ผ๋ ๋ป function echo(item: T): T { return item; }
const r1 = echo(100); // T๋ number๊ฐ ๋จ const r2 = echo("Hi"); // T๋ string์ด ๋จ ```
7.1.2. ํ์ฉ : API ์๋ต ์ฒ๋ฆฌ ๐
interface Response<T> {
data: T; // ์ค์ ๋ฐ์ดํฐ์ ํ์
์ ๊ทธ๋๊ทธ๋ ๋ค๋ฆ!
status: number;
message: string;
}
// ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ๋
const userRes: Response<{ name: string }> = {
data: { name: "์ฒ ์" },
status: 200,
message: "์ฑ๊ณต"
};
// ์ํ ๋ชฉ๋ก์ ๋ฐ์ ๋
const itemRes: Response<string[]> = {
data: ["์ฌ๊ณผ", "๋ฐ๋๋"],
status: 200,
message: "์ฑ๊ณต"
};
7.2. ์ ๋ค๋ฆญ ํจ์์ ์ธํฐํ์ด์ค ๐ ๏ธ
7.2.1. ์ ๋ค๋ฆญ ํจ์ (Generic Functions) โ๏ธ
ํจ์ ์ด๋ฆ ๋ค์ <T>๋ฅผ ๋ถ์ฌ ์ฌ์ฉํฉ๋๋ค. ์ฌ๊ธฐ์ T๋ ๊ด์ต์ ์ผ๋ก ์ฌ์ฉํ๋ ์ด๋ฆ์ผ ๋ฟ์
๋๋ค.
// ๊ดํธ ์ <T>๋ ์ด ํจ์์์ T๋ผ๋ ํ์
๋ณ์๋ฅผ ์ฐ๊ฒ ๋ค๋ ์ ์ธ์
๋๋ค.
function getFirstElement<T>(arr: T[]): T {
return arr[0];
}
// ์ฌ์ฉ ์์ ์ ํ์
์ ๋ช
์ํ๊ฑฐ๋, TS๊ฐ ์ถ๋ก ํ๊ฒ ๋ก๋๋ค.
const str = getFirstElement<string>(["A", "B"]); // T๋ string
const num = getFirstElement([1, 2, 3]); // T๋ number (์๋ ์ถ๋ก )
7.2.2. ์ ๋ค๋ฆญ ์ธํฐํ์ด์ค (Generic Interfaces) ํ ํ๋ฆฟ ๐
์ธํฐํ์ด์ค ์ด๋ฆ ๋ค์ <T>๋ฅผ ๋ถ์
๋๋ค. ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๊ฐ์๋ฐ ๋ด๋ถ ๊ฐ์ ํ์
๋ง ๋ฐ๋ ๋ ์ ์ฉํฉ๋๋ค.
// ์ด๋ค ํํ์ ๋ฐ์ดํฐ(T)๋ ๋ด์ ์ ์๋ ๋ฐ์ค ์ค๊ณ๋
interface Box<T> {
label: string;
content: T;
}
const stringBox: Box<string> = { label: "ํธ์ง", content: "์๋
ํ์ธ์!" };
const numberBox: Box<number> = { label: "๋์ด", content: 25 };
7.2.3. HTTP ์๋ต ์ฒ๋ฆฌ ์์ ๐ก
interface ApiResponse<T> {
success: boolean;
data: T; // ์ฌ๊ธฐ์ ์ด๋ค ๋ฐ์ดํฐ๊ฐ ์ฌ์ง ์ ๋ค๋ฆญ์ผ๋ก ๊ฒฐ์ !
error?: string;
}
interface User { id: number; name: string; }
function fetchUser(): ApiResponse<User> {
return { success: true, data: { id: 1, name: "์ฒ ์" } };
}
const response = fetchUser();
console.log(response.data.name); // 'User' ํ์
์์ ์๊ธฐ์ ์๋์์ฑ ๊ฐ๋ฅ!
7.2.4. ์ฌ๋ฌ ๊ฐ์ ์ ๋ค๋ฆญ ๋ณ์ ์ฌ์ฉ (<T, U, K>) ๐๏ธ
์๋ก ๋ค๋ฅธ ํ์ ์ ๊ฒฐํฉํ๊ฑฐ๋ ๊ด๊ณ๋ฅผ ๋งบ์ด์ค ๋ ์ฌ์ฉํฉ๋๋ค.
function merge<T, U>(objA: T, objB: U): T & U {
return { ...objA, ...objB };
}
const combined = merge({ name: '์ฒ ์' }, { age: 25 });
console.log(combined.name); // OK
console.log(combined.age); // OK
7.2.5. ์ T, U ์ธ๊ฐ์? ๐
๋ณดํต ๊ด์ต์ ์ผ๋ก ์๋ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค. - T: Type (์ฒซ ๋ฒ์งธ) - U: Usually (T ๋ค์ ๋ฌธ์) - K: Key - V: Value - E: Element
7.3. ์ ๋ค๋ฆญ ์ ์ฝ ์กฐ๊ฑด (Constraints) โ
7.3.1. ์ ์ ์ฝ ์กฐ๊ฑด์ด ํ์ํ๊ฐ? (๋ฌธ์ ์ํฉ) โ ๏ธ
๋จ์ํ <T>๋ง ์ฐ๋ฉด TS๋ ์ด๋ค ์์ฑ์ด ๋ค์ด์ฌ์ง ๋ชฐ๋ผ ์๋ฌ๋ฅผ ๋
๋๋ค.
function printLength<T>(item: T) {
// โ ์๋ฌ: 'T' ํ์์ 'length' ์์ฑ์ด ์์ต๋๋ค.
console.log(item.length);
}
7.3.2. extends๋ก ํด๊ฒฐํ๊ธฐ ๐ค
"T๋ ์ ์ด๋ ํน์ ์์ฑ์ ๊ฐ์ง ํ์ ์ด์ด์ผ ํด"๋ผ๊ณ ๊ณ์ฝ์๋ฅผ ์ฐ๋ ๊ฒ์ ๋๋ค.
interface LengthWise { length: number; }
// T๋ ๋ฐ๋์ LengthWise ์ธํฐํ์ด์ค๋ฅผ ๋ง์กฑํด์ผ ํจ
function printLength<T extends LengthWise>(item: T): void {
console.log(`๊ธธ์ด: ${item.length}`); // โ
์ด์ ์์ฌํ๊ณ ์ฌ์ฉ ๊ฐ๋ฅ!
}
printLength("Hello"); // โ
OK
printLength([1, 2, 3]); // โ
OK
// printLength(123); // โ ์๋ฌ! (์ซ์๋ length๊ฐ ์์)
7.3.3. ํน์ ์์ฑ ์ถ์ถ (keyof) ๐
"K๋ ๋ฐ๋์ T์ ํค(Key) ์ค ํ๋์ฌ์ผ ํ๋ค"๋ ์ ์ฝ์ ๋๋ค.
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person = { name: "์ฒ ์", age: 25 };
getProperty(person, "name"); // โ
OK
// getProperty(person, "hobby"); // โ ์๋ฌ! (๊ฐ์ฒด์ hobby ํค๊ฐ ์์)
8. ์ ํธ๋ฆฌํฐ (Utility Types & Modules) ๐ ๏ธ
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
์ ํธ๋ฆฌํฐ ํ์ (Utility Types)์ ์ด๋ฏธ ์ ์ํด๋ ํ์ ์ ์ํฉ์ ๋ง๊ฒ ๋ณํํด์ ์ฐ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ 'ํ์ ์ ์ฉ ๋๊ตฌ'์ ๋๋ค.
8.1. ์ฃผ์ ์ ํธ๋ฆฌํฐ ํ์ ๐งฐ
8.1.1. Partial<T> : ๋ชจ๋ ์์ฑ์ ์ ํ ์ฌํญ์ผ๋ก! โ
๊ธฐ์กด ํ์
์์ ์ํ๋ ์์ฑ๋ง ๊ณจ๋ผ์ ์๋ก์ด ํ์
์ ๋ง๋ญ๋๋ค. Partial<User>๊ฐ ๋ถ์ ๊ณณ์๋ ์์ฑ ์ค ์ผ๋ถ๋ง ๊ณจ๋ผ์ ๋ฃ์ ์ ์์ต๋๋ค.
interface User {
id: number;
name: string;
age: number;
}
function updateUser(id: number, fieldsToUpdate: Partial<User>) {
// ์ค์ ์
๋ฐ์ดํธ ๋ก์ง...
}
updateUser(1, { name: "์์ด๋ฆ" }); // โ
age๋ id๊ฐ ์์ด๋ ์๋ฌ ์ ๋จ!
8.1.2. Pick<T, K> : ํ์ํ ๊ฒ๋ง ์์! ๐
๊ธฐ์กด ํ์ ์์ ์ํ๋ ์์ฑ๋ง ๊ณจ๋ผ์ ์๋ก์ด ํ์ ์ ๋ง๋ญ๋๋ค.
// User์์ 'name'๊ณผ 'age'๋ง ๊ณจ๋ผ์ ์ฐ๊ณ ์ถ์ ๋
type UserPreview = Pick<User, "name" | "age">;
const profile: UserPreview = {
name: "์ฒ ์",
age: 20
};
// profile.id; // โ ์๋ฌ! Pick์ผ๋ก ๊ฐ์ ธ์ค์ง ์์
8.1.3. Omit<T, K> : ํน์ ๊ฒ๋ง ๋นผ๊ณ ์ ๋ถ! โ๏ธ
๊ธฐ์กด ํ์ ์์ ํน์ ์์ฑ๋ง ์ ๊ฑฐํ๊ณ ๋๋จธ์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// User์์ 'id'๋ง ๋นผ๊ณ ๋๋จธ์ง๋ ๋ค ์ฐ๊ณ ์ถ์ ๋
type NewUser = Omit<User, "id">;
const newUser: NewUser = {
name: "์ํฌ",
age: 27
// id ์์ฑ์ ๋ฃ์ผ๋ฉด ์คํ๋ ค ์๋ฌ๋จ!
};
8.1.4. Readonly<T> : ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก! ๐
๋ชจ๋ ์์ฑ์ ์์ ๋ถ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
const frozenUser: Readonly<User> = { id: 1, name: "์ฒ ์", age: 20 };
// frozenUser.name = "๊ธธ๋"; // โ ์๋ฌ! ์ฝ๊ธฐ ์ ์ฉ์
8.1.5. Record<K, T> : ํค-๊ฐ ํํ์ ๊ฐ์ฒด ํ์
๋งคํ ๐บ๏ธ
"ํน์ ํค(K)๋ค์ ๋ชจ์์ ๊ฐ(T)์ ํ์ ์ ๊ณ ์ ํ๊ณ ์ถ์ ๋" ์ฌ์ฉํ๋ฉฐ, ๊ฐ์ฒด์ '์ง๋(Map)'๋ '์ฌ์ '์ ๋ง๋ค ๋ ์ ์ฉํฉ๋๋ค.
8.1.5.1. ๊ธฐ๋ณธ ๋ฌธ๋ฒ ๐
// Record<ํค_ํ์
, ๊ฐ_ํ์
>
const scores: Record<string, number> = {
"math": 100,
"english": 90,
};
8.1.5.2. ์ค๋ฌด ์์ : ์ ํด์ง ์นดํ ๊ณ ๋ฆฌ ๊ด๋ฆฌ ๐๏ธ
ํน์ ๋ฌธ์์ด ์งํฉ์ ํค๋ก ๊ณ ์ ํ ๋ ์ง์ง ์๋ ฅ์ ๋ฐํํฉ๋๋ค.
type Page = "home" | "about" | "contact";
interface PageInfo {
title: string;
}
// "home", "about", "contact" ์ธ์ ํค๋ ํ์ฉํ์ง ์์!
const nav: Record<Page, PageInfo> = {
home: { title: "ํ" },
about: { title: "์๊ฐ" },
contact: { title: "์ฐ๋ฝ์ฒ" },
};
// nav.blog = { title: "๋ธ๋ก๊ทธ" }; // โ ์๋ฌ! Page ํ์
์ 'blog'๊ฐ ์์
8.1.5.3. Record์ ๋ค๋ฅธ ์ ํธ๋ฆฌํฐ ์กฐํฉ ๐ค
๊ฐ์ฒด์ ๊ท๊ฒฉ์ ๋ฑ ์ ํด๋ฒ๋ฆฌ๋ ๋๊ตฌ๋ก ํ์ฉ๋ฉ๋๋ค.
// ์ ์ ๋ค์ ID(number)๋ฅผ ํค๋ก ํ๊ณ , ์ ์ ์ ๋ณด(User)๋ฅผ ๊ฐ์ผ๋ก ํ๋ ๊ฐ์ฒด
const userList: Record<number, User> = {
101: { id: 101, name: "์ฒ ์", age: 20 },
102: { id: 102, name: "์ํฌ", age: 25 },
};
8.2. ๋ชจ๋ ์์คํ ๐ฆ
ํ์ ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ์์คํ ์ ์ฝ๋๋ฅผ ์ฌ๋ฌ ํ์ผ๋ก ๋๋๊ณ ๊ณต์ ํ ์ ์๊ฒ ํด์ฃผ๋ '๋ถํ ๊ด๋ฆฌ ์์คํ '์ ๋๋ค.
8.2.1. ๋ด๋ณด๋ด๊ธฐ (Export) ๐ค
๋ค๋ฅธ ํ์ผ์์ ์ธ ์ ์๋๋ก ์ด๋ฆํ๋ฅผ ๋ถ์ฌ์ฃผ๋ ๋จ๊ณ์ ๋๋ค. - ์ด๋ฆ ๋ถ์ฌ ๋ด๋ณด๋ด๊ธฐ (Named Export): ํ ํ์ผ์์ ์ฌ๋ฌ ๊ฐ๋ฅผ ๋ด๋ณด๋ผ ๋ - ๊ธฐ๋ณธ ๋ด๋ณด๋ด๊ธฐ (Default Export): ํ ํ์ผ์ '๋ํ'๋ฅผ ํ๋๋ง ๋ด๋ณด๋ผ ๋
// math.ts
export const PI = 3.14; // Named Export
export default function add(a: number, b: number) { // Default Export
return a + b;
}
8.2.2. ๊ฐ์ ธ์ค๊ธฐ (Import) ๐ฅ
๋ค๋ฅธ ํ์ผ์ ์๋ ๋ถํ์ ๊ฐ์ ธ์ค๋ ๋จ๊ณ์ ๋๋ค.
// app.ts
import add, { PI } from './math'; // Default๋ ์ค๊ดํธ ์์ด, Named๋ ์ค๊ดํธ ์์!
console.log(add(1, 2)); // 3
console.log(PI); // 3.14
8.2.3. ํ์ ์ ์ฉ ๋ชจ๋ (Import Type) ๐๏ธ
์คํ ๋ฐ์ดํฐ๊ฐ ์๋ '์ค๊ณ๋(ํ์ )'๋ง ๊ฐ์ ธ์ฌ ๋ ์ฌ์ฉํฉ๋๋ค.
// types.ts
export interface User { id: number; name: string; }
// main.ts
import type { User } from './types'; // "๋๋ ํ์
๋ง ์ธ ๊ฑฐ์ผ"๋ผ๊ณ ๋ช
์
const user: User = { id: 1, name: "์ฒ ์" };
9 tsconfig.json ํต์ฌ ์ต์ ๋ค
๋ด์ฉ ํผ์น๊ธฐ / ์ ๊ธฐ
tsconfig.json์ ํ์
์คํฌ๋ฆฝํธ์ ์ปดํ์ผ ํ๊ฒฝ์ ์ค์ ํ๋ ํต์ฌ ํ์ผ์
๋๋ค. ์ค๋ฌด์์ ๊ฐ์ฅ ์์ฃผ ์กฐ์ ํ๋ 5๊ฐ์ง ํต์ฌ ์ต์
์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
9.1. ์ฃผ์ ์ปดํ์ผ ์ต์
target: ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์ด๋ค ๋ฒ์ ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋ณํํ ์ง ๊ฒฐ์ ํฉ๋๋ค. (์:ES6,ESNext)module: ๋ชจ๋ ์์คํ ๋ฐฉ์์ ๊ฒฐ์ ํฉ๋๋ค. (ํ๋ก ํธ์๋ ์ต์ ๋๊ตฌ๋ ์ฃผ๋กESNext, Node.js๋CommonJS)strict: ๋ชจ๋ ํ์ ๊ฒ์ฌ ์ต์ ์ ํ์ฑํํฉ๋๋ค. ์ค๋ฌด์์๋true์ค์ ์ ๊ฐ๋ ฅํ ๊ถ์ฅํฉ๋๋ค.outDir: ์ปดํ์ผ๋ ๊ฒฐ๊ณผ๋ฌผ(.js)์ด ์ ์ฅ๋ ํด๋๋ฅผ ์ง์ ํฉ๋๋ค.paths: ํ๋ก์ ํธ ๋ด์์ ์ ๋ ๊ฒฝ๋ก(์:@/components/...)๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ์ค์ ํ์ฌ ์ฝ๋ ๊ฐ๋ ์ฑ์ ๋์ ๋๋ค.
9.2. ์ค๋ฌด์ฉ ์ถ์ฒ ์ค์ ์์
{
"compilerOptions": {
"target": "ESNext", // ์ต์ JS ๋ฒ์ ์ผ๋ก ๋ณํ
"module": "ESNext", // ์ต์ ๋ชจ๋ ์์คํ
์ฌ์ฉ
"strict": true, // ์๊ฒฉํ ํ์
๊ฒ์ฌ ํ์ฑํ (ํ์)
"outDir": "./dist", // ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ dist ํด๋์ ์ ์ฅ
"rootDir": "./src", // ์์ค ์ฝ๋๋ src ํด๋์์ ์์
"baseUrl": ".", // ๊ฒฝ๋ก ํด์์ ๊ธฐ์ค์
"paths": {
"@/*": ["src/*"] // @/ ๊ธฐํธ๋ก src ํด๋ ์ ๊ทผ ํ์ฉ
},
"esModuleInterop": true, // CommonJS ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธํ์ฑ ํ์ฉ
"skipLibCheck": true, // ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์
๊ฒ์ฌ ์๋ต (๋น๋ ์๋ ํฅ์)
"forceConsistentCasingInFileNames": true // ํ์ผ ์ด๋ฆ์ ๋์๋ฌธ์ ๊ตฌ๋ถ ๊ฐ์
},
"include": ["src/**/*"], // src ํด๋ ๋ด ๋ชจ๋ ํ์ผ ํฌํจ
"exclude": ["node_modules"] // ๊ฒ์ฌ์์ ์ ์ธํ ํด๋
}
9.3. ์์ฝ
- ์ค๊ณ:
target๊ณผmodule๋ก ๊ฒฐ๊ณผ๋ฌผ์ ํธํ์ฑ์ ์ ํฉ๋๋ค. - ์์ :
strict๋ฅผ ํตํด ๋ฐํ์ ์๋ฌ๋ฅผ ๋ฐฉ์งํฉ๋๋ค. - ๊ตฌ์กฐ:
rootDir,outDir,paths๋ก ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.