TypeScript์ ๊ณ ๊ธ ํ์ ์กฐ์ ๊ธฐ๋ฅ์ ํ์ ์ ๊ธ ํด์ ํ์ธ์. ์ด ๊ฐ์ด๋๋ ์กฐ๊ฑด๋ถ ํ์ , ๋งคํ๋ ํ์ , ์ถ๋ก ๋ฑ์ ํ๊ตฌํ์ฌ ๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ๊ธ๋ก๋ฒ ์ํํธ์จ์ด ์์คํ ์ ๊ตฌ์ถํฉ๋๋ค.
ํ์ ์กฐ์: ๊ฒฌ๊ณ ํ ์ํํธ์จ์ด ์ค๊ณ๋ฅผ ์ํ ๊ณ ๊ธ ํ์ ๋ณํ ๊ธฐ๋ฒ
ํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์ ์งํํ๋ ํ๊ฒฝ์์ ํ์ ์์คํ ์ ๋ณต์๋ ฅ ์๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ์ ์ ๋ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ํนํ TypeScript๋ ๊ฐ๋ ฅํ ์ ์ ํ์ดํ ๊ธฐ๋ฅ์ ํตํด JavaScript๋ฅผ ํ์ฅํ๋ฉฐ ๊ฐ๋ ฅํ ํ์ผ๋ก ๋ถ์ํ์ต๋๋ค. ๋ง์ ๊ฐ๋ฐ์๊ฐ ๊ธฐ๋ณธ ํ์ ์ ์ธ์ ์ต์ํ์ง๋ง, TypeScript์ ์ง์ ํ ํ์ ๊ณ ๊ธ ํ์ ์กฐ์ ๊ธฐ๋ฅ์ ์์ต๋๋ค. ์ด๋ ๊ธฐ์กด ํ์ ์ผ๋ก๋ถํฐ ๋์ ์ผ๋ก ์๋ก์ด ํ์ ์ ๋ณํ, ํ์ฅ ๋ฐ ํ์ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฒ์ ๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฅ์ TypeScript๋ฅผ ๋จ์ํ ํ์ ๊ฒ์ฌ๋ฅผ ๋์ด ์ข ์ข "ํ์ ๋ ๋ฒจ ํ๋ก๊ทธ๋๋ฐ"์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ ์์ญ์ผ๋ก ์ด๋๋๋ค.
์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ ๊ณ ๊ธ ํ์ ๋ณํ ๊ธฐ๋ฒ์ ๋ณต์กํ ์ธ๊ณ๋ฅผ ํ๊ตฌํฉ๋๋ค. ์ด๋ฌํ ๊ฐ๋ ฅํ ๋๊ตฌ๊ฐ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ด๋ป๊ฒ ํฅ์์ํค๊ณ , ๊ฐ๋ฐ์ ์์ฐ์ฑ์ ๊ฐ์ ํ๋ฉฐ, ํ์ ์์น๋ ์์ ์ค์ธ ํน์ ๋๋ฉ์ธ์ ๊ด๊ณ์์ด ์ํํธ์จ์ด์ ์ ๋ฐ์ ์ธ ๊ฒฌ๊ณ ์ฑ์ ํฅ์์ํฌ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ฆฌํฉํ ๋ง๋ถํฐ ๊ณ ๋๋ก ํ์ฅ ๊ฐ๋ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ๊น์ง, ํ์ ์กฐ์์ ๋ง์คํฐํ๋ ๊ฒ์ ๊ธ๋ก๋ฒ ๊ฐ๋ฐ ํ๊ฒฝ์์ ํ์ํจ์ ๋ชฉํ๋ก ํ๋ ๋ชจ๋ ์ง์งํ TypeScript ๊ฐ๋ฐ์์๊ฒ ํ์์ ์ธ ๊ธฐ์ ์ ๋๋ค.
ํ์ ์กฐ์์ ๋ณธ์ง: ์ ์ค์ํ๊ฐ
๋ณธ์ง์ ์ผ๋ก ํ์ ์กฐ์์ ์ ์ฐํ๊ณ ์ ์ ๊ฐ๋ฅํ ํ์ ์ ์๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. ๊ธฐ๋ณธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์์ง๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์์๋ ์ฝ๊ฐ ์์ ๋ ๋ฒ์ ์ด ํ์ํ ์๋๋ฆฌ์ค๋ฅผ ์์ํด ๋ณด์ธ์. ์๋ฅผ ๋ค์ด ์ผ๋ถ ์์ฑ์ ์ ํ์ ์ด์ด์ผ ํ๊ณ , ๋ค๋ฅธ ์์ฑ์ ์ฝ๊ธฐ ์ ์ฉ์ด์ด์ผ ํ๊ฑฐ๋, ์์ฑ์ ํ์ ์งํฉ์ ์ถ์ถํด์ผ ํ ์ ์์ต๋๋ค. ์ฌ๋ฌ ํ์ ์ ์๋ฅผ ์๋์ผ๋ก ๋ณต์ ํ๊ณ ์ ์ง ๊ด๋ฆฌํ๋ ๋์ , ํ์ ์กฐ์์ ํตํด ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ์ด๋ฌํ ๋ณํ์ ์์ฑํ ์ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ช ๊ฐ์ง ์ฌ์คํ ์ด์ ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ๋ณต ์ฝ๋ ๊ฐ์: ๋ฐ๋ณต์ ์ธ ํ์ ์ ์ ์์ฑ์ ํผํฉ๋๋ค. ๋จ์ผ ๊ธฐ๋ณธ ํ์ ์์ ์ฌ๋ฌ ํ์ ํ์ ์ ์์ฑํ ์ ์์ต๋๋ค.
- ํฅ์๋ ์ ์ง๋ณด์์ฑ: ๊ธฐ๋ณธ ํ์ ์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ชจ๋ ํ์ ํ์ ์ผ๋ก ์๋ ์ ํ๋์ด ๋๊ท๋ชจ ์ฝ๋๋ฒ ์ด์ค์์ ๋ถ์ผ์น ๋ฐ ์ค๋ฅ ์ํ์ ์ค์ ๋๋ค. ์ด๋ ํ์ ์ ์๊ฐ ๋ถ๊ธฐ๋ ์ ์๋ ์คํด๊ฐ ๋ฐ์ํ ์ ์๋ ์ ์ญ์ ์ผ๋ก ๋ถ์ฐ๋ ํ์๊ฒ ํนํ ์ค์ํฉ๋๋ค.
- ํฅ์๋ ํ์ ์์ ์ฑ: ํ์ ์ ์ฒด๊ณ์ ์ผ๋ก ํ์์ํด์ผ๋ก์จ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์์ ๋ ๋์ ์์ค์ ํ์ ์ ํ์ฑ์ ๋ณด์ฅํ๊ณ ๋ฐํ์์ด ์๋ ์ปดํ์ผ ํ์์ ์ ์ฌ์ ์ธ ๋ฒ๊ทธ๋ฅผ ํฌ์ฐฉํฉ๋๋ค.
- ๋ ํฐ ์ ์ฐ์ฑ๊ณผ ํ์ฅ์ฑ: ํ์ ์์ ์ฑ์ ํฌ์ํ์ง ์์ผ๋ฉด์ ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก์ ๋งค์ฐ ์ ์ ๊ฐ๋ฅํ API ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค๊ณํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ ์์ ์๊ฒ ์๋ฃจ์ ์ ํตํฉํ ์ ์์ต๋๋ค.
- ๋ ๋์ ๊ฐ๋ฐ์ ๊ฒฝํ: ์ง๋ฅํ ํ์ ์ถ๋ก ๋ฐ ์๋ ์์ฑ ๊ธฐ๋ฅ์ด ๋ ์ ํํ๊ณ ์ ์ฉํด์ ธ ๊ฐ๋ฐ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ์ธ์ง ๋ถํ๊ฐ ์ค์ด๋ค์ด ๋ชจ๋ ๊ฐ๋ฐ์์๊ฒ ๋ณดํธ์ ์ธ ์ด์ ์ ์ ๊ณตํฉ๋๋ค.
ํ์ ๋ ๋ฒจ ํ๋ก๊ทธ๋๋ฐ์ ๋งค์ฐ ๋ณํ์ ์ผ๋ก ๋ง๋๋ ๊ณ ๊ธ ๊ธฐ๋ฒ์ ๋ฐ๊ฒฌํ๊ธฐ ์ํ ์ฌ์ ์ ์์ํด ๋ด ์๋ค.
ํต์ฌ ํ์ ๋ณํ ๋น๋ฉ ๋ธ๋ก: ์ ํธ๋ฆฌํฐ ํ์
TypeScript๋ ์ผ๋ฐ์ ์ธ ํ์ ๋ณํ์ ์ํ ๊ธฐ๋ณธ ๋๊ตฌ ์ญํ ์ ํ๋ ์ผ๋ จ์ ๋ด์ฅ "์ ํธ๋ฆฌํฐ ํ์ "์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ํ์ ์ ๋ณต์กํ ๋ณํ์ ๋ง๋ค๊ธฐ ์ ์ ํ์ ์กฐ์์ ์์น์ ์ดํดํ๋ ํ๋ฅญํ ์์์ ์ ๋๋ค.
1. Partial<T>
์ด ์ ํธ๋ฆฌํฐ ํ์ ์ T์ ๋ชจ๋ ์์ฑ์ ์ ํ์ ์ผ๋ก ์ค์ ํ๋ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ข ์ข ๋ชจ๋ ํ๋๊ฐ ์ ๊ณต๋์ง ์๋ ์ ๋ฐ์ดํธ ์์ ์ ์ฌ์ฉ๋๋ ๊ธฐ์กด ๊ฐ์ฒด ์์ฑ์ ํ์ ์งํฉ์ ๋ํ๋ด๋ ํ์ ์ ๋ง๋ค ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
์์:
interface UserProfile { id: string; username: string; email: string; country: string; avatarUrl?: string; }
type PartialUserProfile = Partial<UserProfile>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type PartialUserProfile = { id?: string; username?: string; email?: string; country?: string; avatarUrl?: string; }; */
const updateUserData: PartialUserProfile = { email: 'new.email@example.com' }; const newUserData: PartialUserProfile = { username: 'global_user_X', country: 'Germany' };
2. Required<T>
๋ฐ๋๋ก Required<T>๋ T์ ๋ชจ๋ ์์ฑ์ ํ์์ ์ผ๋ก ์ค์ ํ๋ ํ์ ์ผ๋ก ๊ตฌ์ฑ๋ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ ์ ํ์ ์์ฑ์ ๊ฐ์ง ์ธํฐํ์ด์ค๊ฐ ์์ง๋ง ํน์ ์ปจํ ์คํธ์์๋ ํด๋น ์์ฑ์ด ํญ์ ์กด์ฌํ๋ค๋ ๊ฒ์ ์ ๋ ์ ์ฉํฉ๋๋ค.
์์:
interface Configuration { timeout?: number; retries?: number; apiKey: string; }
type StrictConfiguration = Required<Configuration>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type StrictConfiguration = { timeout: number; retries: number; apiKey: string; }; */
const defaultConfiguration: StrictConfiguration = { timeout: 5000, retries: 3, apiKey: 'XYZ123' };
3. Readonly<T>
์ด ์ ํธ๋ฆฌํฐ ํ์ ์ T์ ๋ชจ๋ ์์ฑ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ค์ ํ๋ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ํนํ ์๋ณธ ๊ฐ์ฒด๋ฅผ ์์ ํด์๋ ์ ๋๋ ํจ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ฑฐ๋ ์ํ ๊ด๋ฆฌ ์์คํ ์ ์ค๊ณํ ๋ ์ ์ฉํฉ๋๋ค.
์์:
interface Product { id: string; name: string; price: number; }
type ImmutableProduct = Readonly<Product>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type ImmutableProduct = { readonly id: string; readonly name: string; readonly price: number; }; */
const catalogItem: ImmutableProduct = { id: 'P001', name: 'Global Widget', price: 99.99 }; // catalogItem.name = 'New Name'; // ์ค๋ฅ: 'name'์(๋) ์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ด๋ฏ๋ก ํ ๋นํ ์ ์์ต๋๋ค.
4. Pick<T, K>
Pick<T, K>๋ T์์ ์์ฑ ์งํฉ K(๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ ๋์จ)๋ฅผ ์ ํํ์ฌ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ ๋ ํฐ ํ์ ์์ ์์ฑ์ ํ์ ์งํฉ์ ์ถ์ถํ๋ ๋ฐ ์๋ฒฝํฉ๋๋ค.
์์:
interface Employee { id: string; name: string; department: string; salary: number; email: string; }
type EmployeeOverview = Pick<Employee, 'name' | 'department' | 'email'>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type EmployeeOverview = { name: string; department: string; email: string; }; */
const hrView: EmployeeOverview = { name: 'Javier Garcia', department: 'Human Resources', email: 'javier.g@globalcorp.com' };
5. Omit<T, K>
Omit<T, K>๋ T์์ ๋ชจ๋ ์์ฑ์ ์ ํํ ๋ค์ K(๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ ๋์จ)๋ฅผ ์ ๊ฑฐํ์ฌ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ Pick<T, K>์ ๋ฐ๋์ด๋ฉฐ ํน์ ์์ฑ์ ์ ์ธํ ํ์ ํ์ ์ ๋ง๋๋ ๋ฐ ๋๊ฐ์ด ์ ์ฉํฉ๋๋ค.
์์:
interface Employee { /* ์์ ๋์ผ */ }
type EmployeePublicProfile = Omit<Employee, 'salary' | 'id'>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type EmployeePublicProfile = { name: string; department: string; email: string; }; */
const publicInfo: EmployeePublicProfile = { name: 'Javier Garcia', department: 'Human Resources', email: 'javier.g@globalcorp.com' };
6. Exclude<T, U>
Exclude<T, U>๋ T์์ U์ ํ ๋น ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋์จ ๋ฉค๋ฒ๋ฅผ ์ ์ธํ์ฌ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ฃผ๋ก ์ ๋์จ ํ์ ์ ์ฌ์ฉ๋ฉ๋๋ค.
์์:
type EventStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'; type ActiveStatus = Exclude<EventStatus, 'completed' | 'failed' | 'cancelled'>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type ActiveStatus = "pending" | "processing"; */
7. Extract<T, U>
Extract<T, U>๋ T์์ U์ ํ ๋น ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋์จ ๋ฉค๋ฒ๋ฅผ ์ถ์ถํ์ฌ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ Exclude<T, U>์ ๋ฐ๋์ ๋๋ค.
์์:
type AllDataTypes = string | number | boolean | string[] | { key: string }; type ObjectTypes = Extract<AllDataTypes, object>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type ObjectTypes = string[] | { key: string }; */
8. NonNullable<T>
NonNullable<T>๋ T์์ null ๋ฐ undefined๋ฅผ ์ ์ธํ์ฌ ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. null ๋๋ undefined ๊ฐ์ด ์์๋์ง ์๋ ํ์ ์ ์๊ฒฉํ๊ฒ ์ ์ํ ๋ ์ ์ฉํฉ๋๋ค.
์์:
type NullableString = string | null | undefined; type CleanString = NonNullable<NullableString>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type CleanString = string; */
9. Record<K, T>
Record<K, T>๋ ์์ฑ ํค๊ฐ K์ด๊ณ ์์ฑ ๊ฐ์ด T์ธ ๊ฐ์ฒด ํ์ ์ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ ๋์ ๋๋ฆฌ ์ ์ฌ ํ์ ์ ๋ง๋๋ ๋ฐ ๊ฐ๋ ฅํฉ๋๋ค.
์์:
type Countries = 'USA' | 'Japan' | 'Brazil' | 'Kenya'; type CurrencyMapping = Record<Countries, string>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type CurrencyMapping = { USA: string; Japan: string; Brazil: string; Kenya: string; }; */
const countryCurrencies: CurrencyMapping = { USA: 'USD', Japan: 'JPY', Brazil: 'BRL', Kenya: 'KES' };
์ด๋ฌํ ์ ํธ๋ฆฌํฐ ํ์ ์ ๊ธฐ๋ณธ์ ๋๋ค. ์ด๋ ๋ฏธ๋ฆฌ ์ ์๋ ๊ท์น์ ๋ฐ๋ผ ํ ํ์ ์ ๋ค๋ฅธ ํ์ ์ผ๋ก ๋ณํํ๋ ๊ฐ๋ ์ ๋ณด์ฌ์ค๋๋ค. ์ด์ ์ด๋ฌํ ๊ท์น์ ์ง์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์กฐ๊ฑด๋ถ ํ์ : ํ์ ๋ ๋ฒจ์ "If-Else"์ ํ
์กฐ๊ฑด๋ถ ํ์ ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ํ์ ์ ์ ์ํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ JavaScript์ ์กฐ๊ฑด๋ถ(์ผํญ) ์ฐ์ฐ์(condition ? trueExpression : falseExpression)์ ์ ์ฌํ์ง๋ง ํ์ ์์ ์๋ํฉ๋๋ค. ๊ตฌ๋ฌธ์ T extends U ? X : Y์ ๋๋ค.
์ด๋ T ํ์ ์ด U ํ์ ์ ํ ๋น ๊ฐ๋ฅํ๋ฉด ๊ฒฐ๊ณผ ํ์ ์ X์ด๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด Y์์ ์๋ฏธํฉ๋๋ค.
์กฐ๊ฑด๋ถ ํ์ ์ ํ์ ์์คํ ์ ๋ ผ๋ฆฌ๋ฅผ ๋์ ํ๊ธฐ ๋๋ฌธ์ ๊ณ ๊ธ ํ์ ์กฐ์์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋์ ๋๋ค.
๊ธฐ๋ณธ ์์:
๊ฐ์ํ๋ NonNullable์ ๋ค์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
type MyNonNullable<T> = T extends null | undefined ? never : T;
type Result1 = MyNonNullable<string | null>; // string type Result2 = MyNonNullable<number | undefined>; // number type Result3 = MyNonNullable<boolean>; // boolean
์ฌ๊ธฐ์ T๊ฐ null ๋๋ undefined์ด๋ฉด (์ ๋์จ ํ์ ์์ ํจ๊ณผ์ ์ผ๋ก ์ ๊ฑฐํ๋ never๋ก ํ์๋จ) ์ ๊ฑฐ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด T๋ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
๋ถ๋ฐฐ ์กฐ๊ฑด๋ถ ํ์ :
์กฐ๊ฑด๋ถ ํ์ ์ ์ค์ํ ๋์์ ์ ๋์จ ํ์ ์ ๋ํ ๋ถ๋ฐฐ์ ๋๋ค. ์กฐ๊ฑด๋ถ ํ์ ์ด ์ผ๋ฐ ํ์ ๋งค๊ฐ๋ณ์(๋ค๋ฅธ ํ์ ์ผ๋ก ๋ํ๋์ง ์์ ํ์ ๋งค๊ฐ๋ณ์)์ ์์ฉํ๋ฉด ์ ๋์จ ๋ฉค๋ฒ์ ๋ถ๋ฐฐ๋ฉ๋๋ค. ์ด๋ ์กฐ๊ฑด๋ถ ํ์ ์ด ์ ๋์จ์ ๊ฐ ๋ฉค๋ฒ์ ๊ฐ๋ณ์ ์ผ๋ก ์ ์ฉ๋๊ณ ๊ฒฐ๊ณผ๊ฐ ์ ์ ๋์จ์ผ๋ก ๊ฒฐํฉ๋จ์ ์๋ฏธํฉ๋๋ค.
๋ถ๋ฐฐ ์์:
ํ์ ์ด ๋ฌธ์์ด ๋๋ ์ซ์์ธ์ง ํ์ธํ๋ ํ์ ์ ์๊ฐํด ๋ณด์ธ์.
type IsStringOrNumber<T> = T extends string | number ? 'stringOrNumber' : 'other';
type Test1 = IsStringOrNumber<string>; // "stringOrNumber" type Test2 = IsStringOrNumber<boolean>; // "other" type Test3 = IsStringOrNumber<string | boolean>; // "stringOrNumber" | "other" (๋ถ๋ฐฐ๋๊ธฐ ๋๋ฌธ)
๋ถ๋ฐฐ๊ฐ ์์ผ๋ฉด Test3์ string | boolean์ด string | number์ ํ ๋น ๊ฐ๋ฅํ์ง ํ์ธ(์ ์ฒด์ ์ผ๋ก๋ ๊ทธ๋ ์ง ์์)ํ๊ณ ์ ์ฌ์ ์ผ๋ก "other"๊ฐ ๋ ๊ฒ์ ๋๋ค. ํ์ง๋ง ๋ถ๋ฐฐ๋๊ธฐ ๋๋ฌธ์ string extends string | number ? ... : ... ๋ฐ boolean extends string | number ? ... : ...๋ฅผ ๋ณ๋๋ก ํ๊ฐํ ๋ค์ ๊ฒฐ๊ณผ๋ฅผ ์ ๋์จํฉ๋๋ค.
์ค์ฉ์ ์ธ ์ ์ฉ: ํ์ ์ ๋์จ ํผ์น๊ธฐ
๊ฐ์ฒด ์ ๋์จ์ด ์๊ณ ๊ณตํต ์์ฑ์ ์ถ์ถํ๊ฑฐ๋ ํน์ ๋ฐฉ์์ผ๋ก ๋ณํฉํ๋ ค๋ ๊ฒฝ์ฐ๋ฅผ ๊ฐ์ ํด ๋ณด์ธ์. ์กฐ๊ฑด๋ถ ํ์ ์ด ํต์ฌ์ ๋๋ค.
type Flatten<T> = T extends infer R ? { [K in keyof R]: R[K] } : never;
์ด ๋จ์ํ Flatten์ ์์ฒด์ ์ผ๋ก ๋ง์ ์์ ์ ์ํํ์ง ๋ชปํ ์ ์์ง๋ง, ํนํ ๋ค์์ ๋ ผ์ํ infer ํค์๋์ ๊ฒฐํฉ๋ ๋ ์กฐ๊ฑด๋ถ ํ์ ์ด ๋ถ๋ฐฐ๋ฅผ ์ํ "ํธ๋ฆฌ๊ฑฐ" ์ญํ ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
์กฐ๊ฑด๋ถ ํ์ ์ ์ ๊ตํ ํ์ ๋ ๋ฒจ ๋ก์ง์ ๊ฐ๋ฅํ๊ฒ ํ์ฌ ๊ณ ๊ธ ํ์ ๋ณํ์ ์ด์์ด ๋ฉ๋๋ค. ์ข ์ข ๋ค๋ฅธ ๊ธฐ๋ฒ, ํนํ infer ํค์๋์ ๊ฒฐํฉ๋ฉ๋๋ค.
์กฐ๊ฑด๋ถ ํ์ ์์์ ์ถ๋ก : 'infer' ํค์๋
infer ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์กฐ๊ฑด๋ถ ํ์ ์ extends ์ ๋ด์์ ํ์ ๋ณ์๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด ๋ณ์๋ฅผ ์ผ์นํ๋ ํ์ ์ "์บก์ฒ"ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์กฐ๊ฑด๋ถ ํ์ ์ ์ฐธ ๋ถ๊ธฐ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. ํ์ ์ ๋ํ ํจํด ๋งค์นญ๊ณผ ๊ฐ์ต๋๋ค.
๊ตฌ๋ฌธ: T extends SomeType<infer U> ? U : FallbackType;
์ด๋ ๋ณต์กํ ํ์ ์ ๋ถ๋ถ์ ๋ถํดํ๊ณ ์ถ์ถํ๋ ๋ฐ ๋งค์ฐ ๊ฐ๋ ฅํฉ๋๋ค. infer์ ๋ฉ์ปค๋์ฆ์ ์ดํดํ๊ธฐ ์ํด infer๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๊ตฌํ๋ ๋ช ๊ฐ์ง ํต์ฌ ์ ํธ๋ฆฌํฐ ํ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. ReturnType<T>
์ด ์ ํธ๋ฆฌํฐ ํ์ ์ ํจ์ ํ์ ์ ๋ฐํ ํ์ ์ ์ถ์ถํฉ๋๋ค. ์ ์ญ ์ ํธ๋ฆฌํฐ ํจ์ ์ธํธ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ ํธ์ถํ์ง ์๊ณ ๋ ์์ฑํ๋ ๋ฐ์ดํฐ์ ์ ํํ ํ์ ์ ์์์ผ ํ๋ค๊ณ ์์ํด ๋ณด์ธ์.
๊ณต์ ๊ตฌํ (๊ฐ์ํ):
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
์์:
function getUserData(userId: string): { id: string; name: string; email: string } { return { id: userId, name: 'John Doe', email: 'john.doe@example.com' }; }
type UserDataType = MyReturnType<typeof getUserData>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type UserDataType = { id: string; name: string; email: string; }; */
2. Parameters<T>
์ด ์ ํธ๋ฆฌํฐ ํ์ ์ ํจ์ ํ์ ์ ๋งค๊ฐ๋ณ์ ํ์ ์ ํํ๋ก ์ถ์ถํฉ๋๋ค. ํ์ ์์ ํ ๋ํผ ๋๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋๋ ๋ฐ ํ์์ ์ ๋๋ค.
๊ณต์ ๊ตฌํ (๊ฐ์ํ):
type MyParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
์์:
function sendNotification(userId: string, message: string, priority: 'low' | 'medium' | 'high'): boolean { console.log(`Sending notification to ${userId}: ${message} with priority ${priority}`); return true; }
type NotificationArgs = MyParameters<typeof sendNotification>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type NotificationArgs = [userId: string, message: string, priority: 'low' | 'medium' | 'high']; */
3. UnpackPromise<T>
์ด๊ฒ์ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๋ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ์ ์ง์ ์ ํธ๋ฆฌํฐ ํ์ ์ ๋๋ค. Promise์์ ํด๊ฒฐ๋ ๊ฐ ํ์ ์ ์ถ์ถํฉ๋๋ค.
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
์์:
async function fetchConfig(): Promise<{ apiBaseUrl: string; timeout: number }> { return { apiBaseUrl: 'https://api.globalapp.com', timeout: 60000 }; }
type ConfigType = UnpackPromise<ReturnType<typeof fetchConfig>>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type ConfigType = { apiBaseUrl: string; timeout: number; }; */
infer ํค์๋๋ ์กฐ๊ฑด๋ถ ํ์ ๊ณผ ํจ๊ป ๋ณต์กํ ํ์ ์ ๋ถ๋ถ์ ์กฐ์ฌํ๊ณ ์ถ์ถํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ ๋ง์ ๊ณ ๊ธ ํ์ ๋ณํ์ ๊ธฐ์ด๋ฅผ ํ์ฑํฉ๋๋ค.
๋งคํ๋ ํ์ : ๊ฐ์ฒด ๋ชจ์์ ์ฒด๊ณ์ ์ผ๋ก ๋ณํ
๋งคํ๋ ํ์ ์ ๊ธฐ์กด ๊ฐ์ฒด ํ์ ์ ์์ฑ์ ๋ณํํ์ฌ ์ ๊ฐ์ฒด ํ์ ์ ๋ง๋๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ์ฃผ์ด์ง ํ์ ์ ํค๋ฅผ ๋ฐ๋ณตํ๊ณ ๊ฐ ์์ฑ์ ๋ณํ์ ์ ์ฉํฉ๋๋ค. ๊ตฌ๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก [P in K]: T[P]์ ๊ฐ์ผ๋ฉฐ, ์ฌ๊ธฐ์ K๋ ์ผ๋ฐ์ ์ผ๋ก keyof T์ ๋๋ค.
๊ธฐ๋ณธ ๊ตฌ๋ฌธ:
type MyMappedType<T> = { [P in keyof T]: T[P]; // ์ค์ ๋ณํ์ ์์ผ๋ฉฐ, ์์ฑ๋ง ๋ณต์ฌํฉ๋๋ค. };
์ด๊ฒ์ด ๊ธฐ๋ณธ ๊ตฌ์กฐ์ ๋๋ค. ๋ง๋ฒ์ ๋๊ดํธ ์์์ ์์ฑ์ด๋ ๊ฐ ํ์ ์ ์์ ํ ๋ ๋ฐ์ํฉ๋๋ค.
์์: `Readonly
type MyReadonly<T> = { readonly [P in keyof T]: T[P]; };
์์: `Partial
type MyPartial<T> = { [P in keyof T]?: T[P]; };
?๋ P in keyof T ๋ค์ ์์ด ์์ฑ์ ์ ํ์ ์ผ๋ก ๋ง๋ญ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก -[P in keyof T]?: T[P]๋ก ์ ํ ์ฌํญ์ ์ ๊ฑฐํ๊ณ -readonly [P in keyof T]: T[P]๋ก ์ฝ๊ธฐ ์ ์ฉ์ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
'as' ์ ์ ์ฌ์ฉํ ํค ์ฌ๋งคํ:
TypeScript 4.1์ ๋งคํ๋ ํ์ ์ as ์ ์ ๋์ ํ์ฌ ์์ฑ ํค๋ฅผ ์ฌ๋งคํํ ์ ์๊ฒ ํ์ต๋๋ค. ์ด๋ ์ ๋์ฌ/์ ๋ฏธ์ฌ ์ถ๊ฐ, ๋์๋ฌธ์ ๋ณ๊ฒฝ ๋๋ ํค ํํฐ๋ง๊ณผ ๊ฐ์ ์์ฑ ์ด๋ฆ ๋ณํ์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌ๋ฌธ: [P in K as NewKeyType]: T[P];
์์: ๋ชจ๋ ํค์ ์ ๋์ฌ ์ถ๊ฐ
type EventPayload = { userId: string; action: string; timestamp: number; };
type PrefixedPayload<T> = { [K in keyof T as `event${Capitalize<string & K>}`]: T[K]; };
type TrackedEvent = PrefixedPayload<EventPayload>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type TrackedEvent = { eventUserId: string; eventAction: string; eventTimestamp: number; }; */
์ฌ๊ธฐ์ Capitalize<string & K>๋ ์ฒซ ๊ธ์๋ฅผ ๋๋ฌธ์๋ก ๋ง๋๋ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ (๋ค์์ ๋ ผ์)์ ๋๋ค. string & K๋ K๊ฐ Capitalize ์ ํธ๋ฆฌํฐ์ ๋ํด ๋ฌธ์์ด ๋ฆฌํฐ๋ด๋ก ์ฒ๋ฆฌ๋๋๋ก ํฉ๋๋ค.
๋งคํ ์ค ์์ฑ ํํฐ๋ง:
as ์ ๋ด์์ ์กฐ๊ฑด๋ถ ํ์ ์ ์ฌ์ฉํ์ฌ ์์ฑ์ ํํฐ๋งํ๊ฑฐ๋ ์กฐ๊ฑด๋ถ๋ก ์ด๋ฆ์ ๋ฐ๊ฟ ์๋ ์์ต๋๋ค. ์กฐ๊ฑด๋ถ ํ์ ์ด never๋ก ํด๊ฒฐ๋๋ฉด ํด๋น ์์ฑ์ ์ ํ์ ์์ ์ ์ธ๋ฉ๋๋ค.
์์: ํน์ ํ์ ์ ์์ฑ ์ ์ธ
type Config = { appName: string; version: number; debugMode: boolean; apiEndpoint: string; };
type StringProperties<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K]; };
type AppStringConfig = StringProperties<Config>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type AppStringConfig = { appName: string; apiEndpoint: string; }; */
๋งคํ๋ ํ์ ์ ๊ฐ์ฒด์ ๋ชจ์์ ๋ณํํ๋ ๋ฐ ๋งค์ฐ ๋ค์ํ๋ฉฐ, ์ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ, API ์ค๊ณ ๋ฐ ์ ์ธ๊ณ ์ฌ๋ฌ ์ง์ญ์ ๊ตฌ์ฑ ์์ ์์ฑ ๊ด๋ฆฌ์์ ์ผ๋ฐ์ ์ธ ์๊ตฌ ์ฌํญ์ ๋๋ค.
ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ : ํ์ ์ ๋ํ ๋ฌธ์์ด ์กฐ์
TypeScript 4.1์ ๋์ ๋ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ ์ JavaScript์ ํ ํ๋ฆฟ ๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ๊ธฐ๋ฅ์ ํ์ ์์คํ ์ผ๋ก ๊ฐ์ ธ์ต๋๋ค. ์ด๋ฅผ ํตํด ๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ ๋์จ ํ์ ๋ฐ ๊ธฐํ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ๊ณผ ์ฐ๊ฒฐํ์ฌ ์ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ํน์ ๋ฌธ์์ด ํจํด์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ํ์ ์ ๋ง๋๋ ๋ฐ ๊ด๋ฒ์ํ ๊ฐ๋ฅ์ฑ์ ์ด์ด์ค๋๋ค.
๊ตฌ๋ฌธ: JavaScript ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐฑํฑ(`)์ ์ฌ์ฉํ์ฌ ํ๋ ์ด์คํ๋(${Type}) ๋ด์ ํ์
์ ํฌํจํฉ๋๋ค.
์์: ๊ธฐ๋ณธ ์ฐ๊ฒฐ
type Greeting = 'Hello'; type Name = 'World' | 'Universe'; type FullGreeting = `${Greeting} ${Name}!`; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type FullGreeting = "Hello World!" | "Hello Universe!"; */
์ด๋ ๊ธฐ์กด ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ๊ธฐ๋ฐ์ผ๋ก ๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ ๋์จ์ ์์ฑํ๋ ๋ฐ ์ด๋ฏธ ๋งค์ฐ ๊ฐ๋ ฅํฉ๋๋ค.
๋ด์ฅ ๋ฌธ์์ด ์กฐ์ ์ ํธ๋ฆฌํฐ ํ์ :
TypeScript๋ ๋ํ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ ์ ํ์ฉํ์ฌ ์ผ๋ฐ์ ์ธ ๋ฌธ์์ด ๋ณํ์ ์ํ ๋ค ๊ฐ์ง ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์ ์ ์ ๊ณตํฉ๋๋ค.
- Capitalize<S>: ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ์ฒซ ๋ฒ์งธ ๋ฌธ์๋ฅผ ๋๋ฌธ์์ ํด๋นํ๋ ๋ฌธ์๋ก ๋ณํํฉ๋๋ค.
- Lowercase<S>: ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ๊ฐ ๋ฌธ์๋ฅผ ์๋ฌธ์์ ํด๋นํ๋ ๋ฌธ์๋ก ๋ณํํฉ๋๋ค.
- Uppercase<S>: ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ๊ฐ ๋ฌธ์๋ฅผ ๋๋ฌธ์์ ํด๋นํ๋ ๋ฌธ์๋ก ๋ณํํฉ๋๋ค.
- Uncapitalize<S>: ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ์ฒซ ๋ฒ์งธ ๋ฌธ์๋ฅผ ์๋ฌธ์์ ํด๋นํ๋ ๋ฌธ์๋ก ๋ณํํฉ๋๋ค.
์ฌ์ฉ ์์:
type Locale = 'en-US' | 'fr-CA' | 'ja-JP'; type EventAction = 'click' | 'hover' | 'submit';
type EventID = `${Uppercase<EventAction>}_${Capitalize<Locale>}`; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type EventID = "CLICK_En-US" | "CLICK_Fr-CA" | "CLICK_Ja-JP" | "HOVER_En-US" | "HOVER_Fr-CA" | "HOVER_Ja-JP" | "SUBMIT_En-US" | "SUBMIT_Fr-CA" | "SUBMIT_Ja-JP"; */
์ด๋ ๊ตญ์ ํ๋ ์ด๋ฒคํธ ID, API ์๋ํฌ์ธํธ ๋๋ CSS ํด๋์ค ์ด๋ฆ๊ณผ ๊ฐ์ ๋ณต์กํ ๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ ๋์จ์ ํ์ ์์ ํ ๋ฐฉ์์ผ๋ก ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
๋์ ํค๋ฅผ ์ํ ๋งคํ๋ ํ์ ๊ณผ์ ๊ฒฐํฉ:
ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ ์ ์ง์ ํ ํ์ ์ข ์ข ํค ์ฌ๋งคํ์ ์ํ as ์ ๊ณผ ๋งคํ๋ ํ์ ๊ณผ ๊ฒฐํฉ๋ ๋ ๋ํ๋ฉ๋๋ค.
์์: ๊ฐ์ฒด์ ๋ํ Getter/Setter ํ์ ์์ฑ
interface Settings { theme: 'dark' | 'light'; notificationsEnabled: boolean; }
type GetterSetters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]; } & { [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void; };
type SettingsAPI = GetterSetters<Settings>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type SettingsAPI = { getTheme: () => "dark" | "light"; getNotificationsEnabled: () => boolean; } & { setTheme: (value: "dark" | "light") => void; setNotificationsEnabled: (value: boolean) => void; }; */
์ด ๋ณํ์ ๊ธฐ๋ณธ Settings ์ธํฐํ์ด์ค์์ ์ง์ getTheme(), setTheme('dark') ๋ฑ๊ณผ ๊ฐ์ ๋ฉ์๋๋ฅผ ์์ฑํ๋ฉฐ, ๋ชจ๋ ๊ฐ๋ ฅํ ํ์ ์์ ์ฑ์ ๊ฐ์ต๋๋ค. ์ด๋ ๋ค์ํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์์๊ฒ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ๊ฐ๋ ฅํ API ๋๋ ๊ตฌ์ฑ ๊ฐ์ฒด์ ๋ํ ๊ฐ๋ ฅํ ํ์ ์ ํด๋ผ์ด์ธํธ ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
์ฌ๊ท ํ์ ๋ณํ: ์ค์ฒฉ๋ ๊ตฌ์กฐ ์ฒ๋ฆฌ
๋ง์ ์ค์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๊น๊ฒ ์ค์ฒฉ๋์ด ์์ต๋๋ค. API์์ ๋ฐํ๋๋ ๋ณต์กํ JSON ๊ฐ์ฒด, ๊ตฌ์ฑ ํธ๋ฆฌ ๋๋ ์ค์ฒฉ๋ ๊ตฌ์ฑ ์์ ์์ฑ์ ์๊ฐํด ๋ณด์ธ์. ์ด๋ฌํ ๊ตฌ์กฐ์ ํ์ ๋ณํ์ ์ ์ฉํ๋ ค๋ฉด ์ข ์ข ์ฌ๊ท์ ์ ๊ทผ ๋ฐฉ์์ด ํ์ํฉ๋๋ค. TypeScript์ ํ์ ์์คํ ์ ์ฌ๊ท๋ฅผ ์ง์ํ์ฌ ์์ฒด๋ฅผ ์ฐธ์กฐํ๋ ํ์ ์ ์ ์ํ ์ ์๊ฒ ํ์ฌ ๋ชจ๋ ๊น์ด์์ ํ์ ์ ํ์ํ๊ณ ์์ ํ ์ ์๋ ๋ณํ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
๊ทธ๋ฌ๋ ํ์ ๋ ๋ฒจ ์ฌ๊ท์๋ ํ๊ณ๊ฐ ์์ต๋๋ค. TypeScript์๋ ์ฌ๊ท ๊น์ด ์ ํ(์ข ์ข ์ฝ 50๋จ๊ณ, ๋ค๋ฅผ ์ ์์)์ด ์์ด ๋ฌดํํ ํ์ ๊ณ์ฐ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ฌ๊ท ํ์ ์ ์ ์คํ๊ฒ ์ค๊ณํ์ฌ ์ด๋ฌํ ์ ํ์ ๋๋ฌํ๊ฑฐ๋ ๋ฌดํ ๋ฃจํ์ ๋น ์ง์ง ์๋๋ก ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์์: DeepReadonly<T>
Readonly<T>๋ ๊ฐ์ฒด์ ์ฆ๊ฐ์ ์ธ ์์ฑ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ง๋ค์ง๋ง ์ค์ฒฉ๋ ๊ฐ์ฒด์๋ ์ฌ๊ท์ ์ผ๋ก ์ ์ฉํ์ง ์์ต๋๋ค. ์ง์ ํ ๋ถ๋ณ ๊ตฌ์กฐ๋ฅผ ์ํด์๋ DeepReadonly๊ฐ ํ์ํฉ๋๋ค.
type DeepReadonly<T> = T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]>; } : T;
์ด๋ฅผ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
- T extends object ? ... : T;: ์ด๊ฒ์ ์กฐ๊ฑด๋ถ ํ์ ์ ๋๋ค. T๊ฐ ๊ฐ์ฒด(๋๋ JavaScript์์๋ ๊ฐ์ฒด์ธ ๋ฐฐ์ด)์ธ์ง ํ์ธํฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์๋ ๊ฒฝ์ฐ(์ฆ, string, number, boolean, null, undefined ๋๋ ํจ์์ ๊ฐ์ ๊ธฐ๋ณธ ์ ํ)๋ ์์ ์ ํ์ ๋ณธ์ง์ ์ผ๋ก ๋ถ๋ณํ๊ธฐ ๋๋ฌธ์ T ์์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- { readonly [K in keyof T]: DeepReadonly<T[K]>; }: T๊ฐ ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ ๋งคํ๋ ํ์ ์ ์ ์ฉํฉ๋๋ค.
- readonly [K in keyof T]: T์ ๊ฐ ์์ฑ K๋ฅผ ๋ฐ๋ณตํ๊ณ readonly๋ก ํ์ํฉ๋๋ค.
- DeepReadonly<T[K]>: ์ค์ํ ๋ถ๋ถ์ ๋๋ค. ๊ฐ ์์ฑ์ ๊ฐ T[K]์ ๋ํด DeepReadonly๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํฉ๋๋ค. ์ด๋ฅผ ํตํด T[K]๊ฐ ์์ฒด ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ ํ๋ก์ธ์ค๊ฐ ๋ฐ๋ณต๋์ด ์ค์ฒฉ๋ ์์ฑ๋ ์ฝ๊ธฐ ์ ์ฉ์ด ๋ฉ๋๋ค.
์ฌ์ฉ ์์:
interface UserSettings { theme: 'dark' | 'light'; notifications: { email: boolean; sms: boolean; }; preferences: string[]; }
type ImmutableUserSettings = DeepReadonly<UserSettings>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type ImmutableUserSettings = { readonly theme: "dark" | "light"; readonly notifications: { readonly email: boolean; readonly sms: boolean; }; readonly preferences: readonly string[]; // ๋ฐฐ์ด ์์๋ ์ฝ๊ธฐ ์ ์ฉ์ด ์๋์ง๋ง ๋ฐฐ์ด ์์ฒด๋ ์ฝ๊ธฐ ์ ์ฉ์ ๋๋ค. }; */
const userConfig: ImmutableUserSettings = { theme: 'dark', notifications: { email: true, sms: false }, preferences: ['darkMode', 'notifications'] };
// userConfig.theme = 'light'; // ์ค๋ฅ! // userConfig.notifications.email = false; // ์ค๋ฅ! // userConfig.preferences.push('locale'); // ์ค๋ฅ! (๋ฐฐ์ด ์ฐธ์กฐ์ ๊ฒฝ์ฐ, ์์๋ ์๋)
์์: DeepPartial<T>
DeepReadonly์ ์ ์ฌํ๊ฒ DeepPartial์ ์ค์ฒฉ๋ ๊ฐ์ฒด์ ์์ฑ์ ํฌํจํ์ฌ ๋ชจ๋ ์์ฑ์ ์ ํ์ ์ผ๋ก ๋ง๋ญ๋๋ค.
type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]>; } : T;
์ฌ์ฉ ์์:
interface PaymentDetails { card: { number: string; expiry: string; }; billingAddress: { street: string; city: string; zip: string; country: string; }; }
type PaymentUpdate = DeepPartial<PaymentDetails>; /* ์ด์ ์์ํ๋ ๋ด์ฉ: type PaymentUpdate = { card?: { number?: string; expiry?: string; }; billingAddress?: { street?: string; city?: string; zip?: string; country?: string; }; }; */
const updateAddress: PaymentUpdate = { billingAddress: { country: 'Canada', zip: 'A1B 2C3' } };
์ฌ๊ท ํ์ ์ ์ํฐํ๋ผ์ดํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ , API ํ์ด๋ก๋ ๋ฐ ๊ธ๋ก๋ฒ ์์คํ ๊ตฌ์ฑ์ ๊ด๋ฆฌํ๋ ๋ฐ ์ผ๋ฐ์ ์ธ ๋ณต์กํ๊ณ ๊ณ์ธต์ ์ธ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ฒ๋ฆฌํ๋ ๋ฐ ํ์์ ์ด๋ฉฐ, ๋ถ๋ถ ์ ๋ฐ์ดํธ ๋๋ ๊น์ ๊ตฌ์กฐ์ ๊ฑธ์น ๋ถ๋ณ ์ํ์ ๋ํ ์ ํํ ํ์ ์ ์๋ฅผ ํ์ฉํฉ๋๋ค.
ํ์ ๊ฐ๋ ๋ฐ ๋จ์ธ ํจ์: ๋ฐํ์ ํ์ ๊ฐ์
ํ์ ์กฐ์์ ์ฃผ๋ก ์ปดํ์ผ ํ์์ ๋ฐ์ํ์ง๋ง, TypeScript๋ ๋ฐํ์์์ ํ์ ์ ๊ฐ์ ํ๋ ๋ฉ์ปค๋์ฆ(ํ์ ๊ฐ๋ ๋ฐ ๋จ์ธ ํจ์)๋ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ ์ ํ์ ๊ฒ์ฌ์ ๋์ JavaScript ์คํ ๊ฐ์ ๊ฒฉ์ฐจ๋ฅผ ํด์ํ์ฌ ๋ฐํ์ ๊ฒ์ฌ๋ฅผ ํตํด ํ์ ์ ์ขํ ์ ์๊ฒ ํด์ฃผ๋ฉฐ, ์ด๋ ๋ค์ํ ๊ธ๋ก๋ฒ ์์ค์์ ์ค๋ ๋ค์ํ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
ํ์ ๊ฐ๋ (์ ์ด ํจ์)
ํ์ ๊ฐ๋๋ ๋ถ์ธ ๊ฐ์ ๋ฐํํ๋ ํจ์์ด๋ฉฐ, ๋ฐํ ํ์ ์ ํ์ ์ ์ด์ ๋๋ค. ํ์ ์ ์ด๋ parameterName is Type ํํ๋ฅผ ์ฌ์ฉํฉ๋๋ค. TypeScript๊ฐ ํ์ ๊ฐ๋๊ฐ ํธ์ถ๋๋ ๊ฒ์ ๋ณด๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๋ฒ์ ๋ด์ ๋ณ์ ํ์ ์ ์ขํ๋๋ค.
์์: ์ฐจ๋ณํ๋ ์ ๋์จ ํ์
interface SuccessResponse { status: 'success'; data: any; } interface ErrorResponse { status: 'error'; message: string; code: number; } type ApiResponse = SuccessResponse | ErrorResponse;
function isSuccessResponse(response: ApiResponse): response is SuccessResponse { return response.status === 'success'; }
function handleResponse(response: ApiResponse) { if (isSuccessResponse(response)) { console.log('Data received:', response.data); // 'response'๋ ์ด์ SuccessResponse๋ก ์๋ ค์ง๋๋ค. } else { console.error('Error occurred:', response.message, 'Code:', response.code); // 'response'๋ ์ด์ ErrorResponse๋ก ์๋ ค์ง๋๋ค. } }
ํ์ ๊ฐ๋๋ ํนํ ์ฑ๊ณต ๋๋ ์คํจ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ๋ฐํํ๋ API์ ๊ฐ์ ์ธ๋ถ ์์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์ ์ญ ์ด๋ฒคํธ ๋ฒ์ค์ ๋ค๋ฅธ ๋ฉ์์ง ์ ํ์ ์ฒ๋ฆฌํ ๋ ์ ๋์จ ํ์ ์ ์์ ํ๊ฒ ๋ค๋ฃจ๋ ๋ฐ ๊ธฐ๋ณธ์ ๋๋ค.
๋จ์ธ ํจ์
TypeScript 3.7์ ๋์ ๋ ๋จ์ธ ํจ์๋ ํ์ ๊ฐ๋์ ์ ์ฌํ์ง๋ง ๋ชฉํ๊ฐ ๋ค๋ฆ ๋๋ค. ์กฐ๊ฑด์ ์ฐธ์ด๋ผ๊ณ ๋จ์ธํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ ๊ฒ์ ๋๋ค. ๋ฐํ ํ์ ์ asserts condition ๊ตฌ๋ฌธ์ ์ฌ์ฉํฉ๋๋ค. asserts ์๋ช ์ ๊ฐ์ง ํจ์๊ฐ ์ค๋ฅ๋ฅผ ๋ฐ์์ํค์ง ์๊ณ ๋ฐํ๋๋ฉด TypeScript๋ ๋จ์ธ์ ๋ฐ๋ผ ์ธ์์ ํ์ ์ ์ขํ๋๋ค.
์์: null์ด ์๋ ๊ฐ ๋จ์ธ
function assertIsDefined<T>(val: T, message?: string): asserts val is NonNullable<T> { if (val === undefined || val === null) { throw new Error(message || 'Value must be defined'); } }
function processConfig(config: { baseUrl?: string; retries?: number }) { assertIsDefined(config.baseUrl, 'Base URL is required for configuration'); // ์ด ์ค ์ดํ, config.baseUrl์ 'string | undefined'๊ฐ ์๋๋ผ 'string'์ผ๋ก ๋ณด์ฅ๋ฉ๋๋ค. console.log('Processing data from:', config.baseUrl.toUpperCase()); if (config.retries !== undefined) { console.log('Retries:', config.retries); } }
๋จ์ธ ํจ์๋ ์ฌ์ ์กฐ๊ฑด์ ๊ฐ์ ํ๊ณ , ์ ๋ ฅ์ ์ ํจ์ฑ ๊ฒ์ฌํ๋ฉฐ, ์์ ์ ๊ณ์ํ๊ธฐ ์ ์ ์ค์ํ ๊ฐ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ ๋ฐ ํ์ํฉ๋๋ค. ์ด๋ ํนํ ๋ฐ์ดํฐ๊ฐ ์ ๋ขฐํ ์ ์๋ ์์ค ๋๋ ๋ค์ํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ํ๋ ์ฌ์ฉ์ ์ ๋ ฅ ์์์์ ์ฌ ์ ์๋ ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ์์ ๊ฒฌ๊ณ ํ ์์คํ ์ค๊ณ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
ํ์ ๊ฐ๋์ ๋จ์ธ ํจ์ ๋ชจ๋ TypeScript์ ์ ์ ํ์ ์์คํ ์ ๋์ ์์๋ฅผ ์ ๊ณตํ์ฌ ๋ฐํ์ ๊ฒ์ฌ๊ฐ ์ปดํ์ผ ํ์ ํ์ ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋๋ก ํ์ฌ ์ ๋ฐ์ ์ธ ์ฝ๋ ์์ ์ฑ๊ณผ ์์ธก ๊ฐ๋ฅ์ฑ์ ๋์ ๋๋ค.
์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ณ ๊ธ ํ์ ๋ณํ ๊ธฐ๋ฒ์ ๋ง์คํฐํ๋ ๊ฒ์ ๋จ์ํ ํ์ ์ ์ฐ์ต์ด ์๋๋๋ค. ํนํ ์ ์ญ์ ์ผ๋ก ๋ถ์ฐ๋ ๊ฐ๋ฐ ํ์์ ๊ณ ํ์ง ์ํํธ์จ์ด๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ์ฌ์คํ ์ค์ง์ ์ธ ์๋ฏธ๊ฐ ์์ต๋๋ค.
1. ๊ฒฌ๊ณ ํ API ํด๋ผ์ด์ธํธ ์์ฑ
REST ๋๋ GraphQL API๋ฅผ ์๋นํ๋ค๊ณ ์์ํด ๋ณด์ธ์. ๋ชจ๋ ์๋ํฌ์ธํธ์ ๋ํ ์๋ต ์ธํฐํ์ด์ค๋ฅผ ์๋์ผ๋ก ์ ๋ ฅํ๋ ๋์ , ํต์ฌ ํ์ ์ ์ ์ํ ๋ค์ ๋งคํ, ์กฐ๊ฑด๋ถ ๋ฐ ์ถ๋ก ํ์ ์ ์ฌ์ฉํ์ฌ ์์ฒญ, ์๋ต ๋ฐ ์ค๋ฅ์ ๋ํ ํด๋ผ์ด์ธํธ ์ธก ํ์ ์ ์์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด GraphQL ์ฟผ๋ฆฌ ๋ฌธ์์ด์ ์์ ํ ํ์ํ๋ ๊ฒฐ๊ณผ ๊ฐ์ฒด๋ก ๋ณํํ๋ ํ์ ์ ๊ณ ๊ธ ํ์ ์กฐ์์ ์ข์ ์์ ๋๋ค. ์ด๋ ๋ค์ํ ํด๋ผ์ด์ธํธ์ ์ฌ๋ฌ ์ง์ญ์ ๋ฐฐํฌ๋ ๋ง์ดํฌ๋ก์๋น์ค ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค.
2. ํ๋ ์์ํฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ
React, Vue, Angular์ ๊ฐ์ ์ฃผ์ ํ๋ ์์ํฌ ๋๋ Redux Toolkit๊ณผ ๊ฐ์ ์ ํธ๋ฆฌํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ฅญํ ๊ฐ๋ฐ์ ๊ฒฝํ์ ์ ๊ณตํ๊ธฐ ์ํด ํ์ ์กฐ์์ ํฌ๊ฒ ์์กดํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์์ฑ, ์ํ, ์ก์ ์์ฑ์ ๋ฐ ์ ํ๊ธฐ์ ํ์ ์ ์ถ๋ก ํ๋ฏ๋ก ๊ฐ๋ฐ์๋ ๊ฐ๋ ฅํ ํ์ ์์ ์ฑ์ ์ ์งํ๋ฉด์ ๋ ์ ์ ๋ฐ๋ณต ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ฌํ ํ์ฅ์ฑ์ ์ ์ธ๊ณ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ์์ ์ฑํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ค์ํฉ๋๋ค.
3. ์ํ ๊ด๋ฆฌ ๋ฐ ๋ถ๋ณ์ฑ
๋ณต์กํ ์ํ๊ฐ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ๋ ๊ฒ์ด ์์ธก ๊ฐ๋ฅํ ๋์์ ํต์ฌ์ ๋๋ค. DeepReadonly ํ์ ์ ์ปดํ์ผ ํ์์ ์ด๋ฅผ ๊ฐ์ ํ์ฌ ์๋ํ์ง ์์ ์์ ์ ๋ฐฉ์งํฉ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก, ์ํ ์ ๋ฐ์ดํธ์ ๋ํ ์ ํํ ํ์ ์ ์ ์ํ๋ฉด(์: ํจ์น ์์ ์ ์ํ DeepPartial ์ฌ์ฉ) ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์๋น์คํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์์ ์ธ ์ํ ์ผ๊ด์ฑ ๊ด๋ จ ๋ฒ๊ทธ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค.
4. ๊ตฌ์ฑ ๊ด๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์๋ ์ข ์ข ๋ณต์กํ ๊ตฌ์ฑ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค. ํ์ ์กฐ์์ ์๊ฒฉํ ๊ตฌ์ฑ์ ์ ์ํ๊ณ , ํ๊ฒฝ๋ณ๋ก ์ฌ์ ์๋ฅผ ์ ์ฉํ๊ฑฐ๋(์: ๊ฐ๋ฐ ๋ ํ๋ก๋์ ํ์ ), ์คํค๋ง ์ ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ฑ ํ์ ์ ์์ฑํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ ์ฌ์ ์ผ๋ก ๋ค๋ฅธ ๋๋ฅ์ ๊ฑธ์น ๋ค์ํ ๋ฐฐํฌ ํ๊ฒฝ์ด ์๊ฒฉํ ๊ท์น์ ์ค์ํ๋ ๊ตฌ์ฑ์ ์ฌ์ฉํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
5. ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ
์ด๋ฒคํธ๊ฐ ๋ค๋ฅธ ๊ตฌ์ฑ ์์ ๋๋ ์๋น์ค ๊ฐ์ ํ๋ฅด๋ ์์คํ ์์๋ ๋ช ํํ ์ด๋ฒคํธ ํ์ ์ ์ ์ํ๋ ๊ฒ์ด ๋ฌด์๋ณด๋ค ์ค์ํฉ๋๋ค. ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ ์ ์ฌ์ฉํ์ฌ ๊ณ ์ ํ ์ด๋ฒคํธ ID(์: USER_CREATED_V1)๋ฅผ ์์ฑํ ์ ์์ผ๋ฉฐ, ์กฐ๊ฑด๋ถ ํ์ ์ ๋ค๋ฅธ ์ด๋ฒคํธ ํ์ด๋ก๋๋ฅผ ๊ตฌ๋ณํ๋ ๋ฐ ๋์์ด ๋์ด ์์คํ ์ ๋์จํ๊ฒ ๊ฒฐํฉ๋ ๋ถ๋ถ ๊ฐ์ ๊ฐ๋ ฅํ ํต์ ์ ๋ณด์ฅํฉ๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก:
- ๋จ์ํ๊ฒ ์์ํ์ธ์: ์ฆ์ ๊ฐ์ฅ ๋ณต์กํ ์๋ฃจ์ ์ผ๋ก ๋ฐ์ด๋ค์ง ๋ง์ธ์. ๊ธฐ๋ณธ ์ ํธ๋ฆฌํฐ ํ์ ์ผ๋ก ์์ํ๊ณ ํ์ํ ๋๋ง ๋ณต์ก์ฑ์ ์ถ๊ฐํ์ธ์.
- ์ฒ ์ ํ๊ฒ ๋ฌธ์ํํ์ธ์: ๊ณ ๊ธ ํ์ ์ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. JSDoc ์ฃผ์์ ์ฌ์ฉํ์ฌ ๋ชฉ์ , ์์ ์ ๋ ฅ ๋ฐ ์ถ๋ ฅ์ ์ค๋ช ํ์ธ์. ์ด๋ ๋ชจ๋ ํ, ํนํ ๋ค์ํ ์ธ์ด ๋ฐฐ๊ฒฝ์ ๊ฐ์ง ํ์๊ฒ ์ค์ํฉ๋๋ค.
- ํ์ ์ ํ ์คํธํ์ธ์: ๋ค, ํ์ ์ ํ ์คํธํ ์ ์์ต๋๋ค! tsd(TypeScript Definition Tester)์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ๊ฐ๋จํ ํ ๋น์ ์์ฑํ์ฌ ํ์ ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ์ธ์.
- ์ฌ์ฌ์ฉ์ฑ ์ฐ์ : ์ผํ์ฑ ์์ ํ์ ์ ์ ๋์ ์ฝ๋๋ฒ ์ด์ค ์ ๋ฐ์ ๊ฑธ์ณ ์ฌ์ฌ์ฉํ ์ ์๋ ๋ฒ์ฉ ์ ํธ๋ฆฌํฐ ํ์ ์ ๋ง๋์ธ์.
- ๋ณต์ก์ฑ๊ณผ ๋ช ํ์ฑ์ ๊ท ํ: ๊ฐ๋ ฅํ์ง๋ง ์ง๋์น๊ฒ ๋ณต์กํ ํ์ ๋ง๋ฒ์ ์ ์ง ๊ด๋ฆฌ ๋ถ๋ด์ด ๋ ์ ์์ต๋๋ค. ํ์ ์ ์๋ฅผ ์ดํดํ๋ ์ธ์ง ๋ถํ๋ณด๋ค ํ์ ์์ ์ฑ์ ์ด์ ์ด ๋ ํฐ ๊ท ํ์ ์ถ๊ตฌํ์ธ์.
- ์ปดํ์ผ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: ๋งค์ฐ ๋ณต์กํ๊ฑฐ๋ ๊น๊ฒ ์ฌ๊ท์ ์ธ ํ์ ์ ๋๋๋ก TypeScript ์ปดํ์ผ์ ๋๋ฆฌ๊ฒ ํ ์ ์์ต๋๋ค. ์ฑ๋ฅ ์ ํ๊ฐ ๊ฐ์ง๋๋ฉด ํ์ ์ ์๋ฅผ ๋ค์ ๊ฒํ ํ์ธ์.
๊ณ ๊ธ ์ฃผ์ ๋ฐ ๋ฏธ๋ ๋ฐฉํฅ
ํ์ ์กฐ์์ ๋ํ ์ฌ์ ์ ์ฌ๊ธฐ์ ๋๋์ง ์์ต๋๋ค. TypeScript ํ์ ๋์์์ด ํ์ ํ๊ณ ์์ผ๋ฉฐ, ์ปค๋ฎค๋ํฐ๋ ๋์ฑ ์ ๊ตํ ๊ฐ๋ ์ ์ ๊ทน์ ์ผ๋ก ํ๊ตฌํ๊ณ ์์ต๋๋ค.
๋ช ๋ชฉ์ vs. ๊ตฌ์กฐ์ ํ์ดํ
TypeScript๋ ๊ตฌ์กฐ์ ์ผ๋ก ํ์ดํ๋์ด ๋ ํ์ ์ด ๋์ผํ ๋ชจ์์ ๊ฐ์ง๊ณ ์์ผ๋ฉด ์ ์ธ๋ ์ด๋ฆ์ ๊ด๊ณ์์ด ํธํ๋ฉ๋๋ค. ๋์กฐ์ ์ผ๋ก, C# ๋๋ Java์ ๊ฐ์ ์ธ์ด์์ ๋ฐ๊ฒฌ๋๋ ๋ช ๋ชฉ์ ํ์ดํ์ ํ์ ์ด ๋์ผํ ์ ์ธ ๋๋ ์์ ์ฒด์ธ์ ๊ณต์ ํ๋ ๊ฒฝ์ฐ์๋ง ํธํ๋๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํฉ๋๋ค. TypeScript์ ๊ตฌ์กฐ์ ํน์ฑ์ด ์ข ์ข ์ ์ตํ์ง๋ง, ๋ช ๋ชฉ์ ๋์์ด ๋ฐ๋์งํ ์๋๋ฆฌ์ค๊ฐ ์์ต๋๋ค(์: UserID ํ์ ๊ณผ ProductID ํ์ ์ ํ ๋นํ์ง ๋ชปํ๊ฒ ํ๋ ๊ฒ, ๋ ๋ค string์ผ์ง๋ผ๋).
ํ์ ๋ธ๋๋ฉ ๊ธฐ๋ฒ์ ๊ณ ์ ํ ๊ธฐํธ ์์ฑ ๋๋ ๋ฆฌํฐ๋ด ์ ๋์จ์ ๊ต์ฐจ ํ์ ๊ณผ ํจ๊ป ์ฌ์ฉํ์ฌ ๋ช ๋ชฉ์ ํ์ดํ์ TypeScript์์ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ต๋๋ค. ์ด๋ ๊ตฌ์กฐ์ ์ผ๋ก ๋์ผํ์ง๋ง ๊ฐ๋ ์ ์ผ๋ก ๋ค๋ฅธ ํ์ ์ ๋ง๋ค๊ธฐ ์ํด ๋ ๊ฐ๋ ฅํ ๊ตฌ๋ถ์ ๋ง๋๋ ๊ณ ๊ธ ๊ธฐ์ ์ ๋๋ค.
์์ (๊ฐ์ํ):
type Brand<T, B> = T & { __brand: B }; type UserID = Brand<string, 'UserID'>; type ProductID = Brand<string, 'ProductID'>;
function getUser(id: UserID) { /* ... */ } function getProduct(id: ProductID) { /* ... */ }
const myUserId: UserID = 'user-123' as UserID; const myProductId: ProductID = 'prod-456' as ProductID;
getUser(myUserId); // OK // getUser(myProductId); // ์ค๋ฅ: 'ProductID' ํ์ ์ 'UserID' ํ์ ์ ํ ๋นํ ์ ์์ต๋๋ค.
ํ์ ๋ ๋ฒจ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์
ํ์ ์ด ๋ ๋์ ์ด๊ณ ํํ๋ ฅ์ด ํ๋ถํด์ง์ ๋ฐ๋ผ ๊ฐ๋ฐ์๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ฐ์์ํค๋ ํ์ ๋ ๋ฒจ ํ๋ก๊ทธ๋๋ฐ ํจํด์ ํ๊ตฌํ๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ํ์ ๋ ๋ฒจ ๋ฆฌ์คํธ, ์ํ ๋จธ์ , ์ฌ์ง์ด ํ์ ์์คํ ๋ด์์๋ง ์๋ํ๋ ๊ธฐ๋ณธ์ ์ธ ์ปดํ์ผ๋ฌ๋ ํฌํจ๋ฉ๋๋ค. ์ผ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์๋ ์ข ์ข ๋๋ฌด ๋ณต์กํ์ง๋ง, ์ด๋ฌํ ํ๊ตฌ๋ ๊ฐ๋ฅํ ๊ฒ์ ๊ฒฝ๊ณ๋ฅผ ํ์ฅํ๊ณ ํฅํ TypeScript ๊ธฐ๋ฅ์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
๊ฒฐ๋ก
TypeScript์ ๊ณ ๊ธ ํ์ ๋ณํ ๊ธฐ๋ฒ์ ๋จ์ํ ๊ตฌ๋ฌธ ์คํ ์ด์์ ๋๋ค. ๋ณต์กํ๊ณ , ๋ณต์๋ ฅ ์๊ณ , ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์ํํธ์จ์ด ์์คํ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ธฐ๋ณธ ๋๊ตฌ์ ๋๋ค. ์กฐ๊ฑด๋ถ ํ์ , ๋งคํ๋ ํ์ , infer ํค์๋, ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ํ์ ๋ฐ ์ฌ๊ท ํจํด์ ํ์ฉํ๋ฉด ๋ ์ ์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ๋ ๋ง์ ์ค๋ฅ๋ฅผ ์ปดํ์ผ ํ์์ ํฌ์ฐฉํ๋ฉฐ, ์ ์ฐํ๊ณ ๋งค์ฐ ๊ฒฌ๊ณ ํ API๋ฅผ ์ค๊ณํ๋ ํ์ ์ป๊ฒ ๋ฉ๋๋ค.
์ํํธ์จ์ด ์ฐ์ ์ด ๊ณ์ ์ธ๊ณํ๋จ์ ๋ฐ๋ผ ๋ช ํํ๊ณ ๋ชจํธํ์ง ์์ผ๋ฉฐ ์์ ํ ์ฝ๋ ๊ดํ์ ๋ํ ํ์์ฑ์ด ๋์ฑ ์ค์ํด์ง๊ณ ์์ต๋๋ค. TypeScript์ ๊ณ ๊ธ ํ์ ์์คํ ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ฐ ๋์์ ์ ์ํ๊ณ ์ํํ๊ธฐ ์ํ ๋ณดํธ์ ์ธ ์ธ์ด๋ฅผ ์ ๊ณตํ์ฌ ๋ค์ํ ๋ฐฐ๊ฒฝ์ ๊ฐ์ง ํ์ด ํจ๊ณผ์ ์ผ๋ก ํ์ ํ๊ณ ๊ณ ํ์ง ์ ํ์ ์ ๊ณตํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ์ ์ ๋ง์คํฐํ๋ ๋ฐ ์๊ฐ์ ํฌ์ํ๋ฉด TypeScript ๊ฐ๋ฐ ์ฌ์ ์์ ์๋ก์ด ์์ค์ ์์ฐ์ฑ๊ณผ ์์ ๊ฐ์ ์ป๊ฒ ๋ ๊ฒ์ ๋๋ค.
ํ๋ก์ ํธ์์ ๊ฐ์ฅ ์ ์ฉํ๋ ๊ณ ๊ธ ํ์ ์กฐ์์ ๋ฌด์์ด์๋์? ์๋ ๋๊ธ์์ ์ธ์ฌ์ดํธ์ ์๋ฅผ ๊ณต์ ํด ์ฃผ์ธ์!