[TS] ํ์ ์คํฌ๋ฆฝํธ ๋งต๋ ํ์ / ์ ํธ๋ฆฌํฐ ํ์ / Enum
ํ์
์คํฌ๋ฆฝํธ์ ๋งต๋ ํ์
(Mapped Types)์ ๊ธฐ์กด ํ์
์ ์๋ก์ด ํ์
์ผ๋ก ๋ณํํด์ฃผ๋ ๋ฌธ๋ฒ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ map
๋ฐฐ์ด ๋ฉ์๋๋ฅผ ํ์
์ ์ ์ฉํ ๊ฒ๊ณผ ๋น์ทํ๋ค(๊ทธ๋์ ์ด๋ฆ์ด Mapped Types๋ค).
๋งต๋ ํ์ ๊ฐ๋ ํบ์๋ณด๊ธฐ
์๋ ๋๋ฐ์ด์ค ๋ธ๋๋๋ฅผ ๋ํ๋ด๋ ์ ๋์จ ํ์
Devices
๊ฐ ์๋ค. ์ฌ๊ธฐ์ ๊ฐ ๋๋ฐ์ด์ค ๋ธ๋๋์ ๊ฐ๊ฒฉ ์ ๋ณด๊ฐ ํฌํจ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ถ์ ๋ ๋งต๋ ํ์
์ ํ์ฉํ ์ ์๋ค.
type Devices = 'APPLE' | 'OPPO' | 'XIAOMI'; // ๋๋ฐ์ด์ค ๋ธ๋๋๋ฅผ ๋ํ๋ด๋ ์ ๋์จ ํ์
type DevicePrices = { [P in Devices]: number }; // ๋๋ฐ์ด์ค ๋ธ๋๋ ํ์
์ ์ํํด์ key๋ก ์ ์๋๋ ๋งต๋ ํ์
const deviceInfo: DevicePrices = {
APPLE: 1_200_000, // ์ธ๋์ค์ฝ์ด "_"๋ฅผ ์ด์ฉํด ์ซ์๋ฅผ ๊ตฌ๋ถํ๋ Numeric Seperators ๋ฌธ๋ฒ
OPPO: 800_000,
XIAOMI: 700_000,
};
[P in Devices]
์ฝ๋๋ Devices
ํ์
์ ๊ฐ ๋ฌธ์์ด์ ์ํํ ํ number
ํ์
์ ๊ฐ์ผ๋ก ๊ฐ์ง๋ ๊ฐ์ฒด์ ํค๋ก ์ ์๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ for in
๋ฌธ๋ฒ๊ณผ ๋น์ทํ๋ค. ํค ๋ถ๋ถ์ ์ ๋์จ ํ์
์ ์ง์ ๋ช
์ํ ์๋ ์๋ค.
type DevicePrices = { [P in 'APPLE' | 'OPPO' | 'XIAOMI']: number };
๋งต๋ ํ์
์ ์ฌ์ฉํ์ง ์์๋ค๋ฉด ์๋์ฒ๋ผ ๊ฐ ๋ธ๋๋๋ง๋ค number
ํ์
์ ์ผ์ผ์ด ์ ์ํด์ผ ํ๋ค.
type DevicePrices = {
APPLE: number;
OPPO: number;
XIAOMI: number;
};
๋งต๋ ํ์ ์์
์๋ธ์ ํ์
์๋ Subset
๋งต๋ ํ์
์ ์ธํฐํ์ด์ค ๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ ์ํ๋ ํ์
์ ๋ฐ์, ํด๋น ๊ฐ์ฒด์ ํ์
์ ๋ถ๋ถ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ ํ์
์ผ๋ก ๋ณํํด์ค๋ค(๋ถ๋ถ ์งํฉ์ ๋ง์กฑํ๋ ํ์
์ผ๋ก ๋ณํ).
type Subset<T> = { [P in keyof T]?: T[P] };
// keyof T : T๋ก ๋ฐ์ ๊ฐ์ฒด์ ๋ชจ๋ ์์ฑ๋ช
์ ์ ๋์จ ํ์
์ผ๋ก ๋์ด
// [P in keyof T]?... : T ๊ฐ์ฒด์ ์์ฑ ๊ฐ ์์ฒด๋ฅผ ํ์
์ผ๋ก ๋ง๋ฆ. ๋ฌผ์ํ๋ฅผ ๋ถ์์ผ๋ฏ๋ก ์ ํ์ ์์ฑ
interface Student {
name: string;
age: number;
}
const ageOnly: Subset<Student> = { age: 18 }; // OK
const nameOnly: Subset<Student> = { name: 'Smith' }; // OK
const smith: Subset<Student> = { name: 'Smith', age: 18 }; // OK
const empty: Subset<Student> = {}; // OK (์ ํ ์์ฑ์ด๋ฏ๋ก)
Boolean ํ์ ์ผ๋ก ๋ณํ
๊ธฐ์กด ์ธํฐํ์ด์ค์ ๋ชจ๋ ์์ฑ์ Boolean ํ์ ์ผ๋ก ๋ณํํด์ฃผ๋ ๋งต๋ ํ์ ์ ๋ง๋ค ์ ์๋ค. ์์์ ์ดํด๋ดค๋ ์๋ธ์ (๋ถ๋ถ ์งํฉ) ํ์ ์ผ๋ก ๋ณํํ๋ ๋งต๋ ํ์ ๊ณผ ๊ฐ์ ์๋ฆฌ๋ค.
type MakeBoolean<T> = { [P in keyof T]?: boolean };
// keyof T : T๋ก ๋ฐ์ ๊ฐ์ฒด์ ๋ชจ๋ ์์ฑ๋ช
์ ์ ๋์จ ํ์
์ผ๋ก ๋์ด
// [P in keyof T]?... : T์ ๋ชจ๋ ์์ฑ ๊ฐ์ Boolean ํ์
์ผ๋ก ๋ง๋ฆ. ๋ฌผ์ํ๋ฅผ ๋ถ์์ผ๋ฏ๋ก ์ ํ์ ์์ฑ
interface Student {
name: string;
age: number;
}
const studentMap: MakeBoolean<Student> = {
name: true, // OK
age: undefined, // OK (์ ํ ์์ฑ์ด๋ฏ๋ก)
};
studentMap.name = 3; // Error (boolean ํ์
์ด ์๋๋ฏ๋ก)
์ ํธ๋ฆฌํฐ ํ์
ํ์ ์ฌํ์ฉ — Partial
Partial<Type>
๐ก Readonly
, Partial
, Required
, Pick
, Omit
๋ฑ์ ํ์
์คํฌ๋ฆฝํธ์ ์ด๋ฏธ ๋ด์ฅ๋์ด ์๋ ์ ํธ๋ฆฌํฐ ํ์
์ด๋ค. ๋ ๋ง์ ์ ํธ๋ฆฌํฐ ํ์
์ ๊ณต์ ๋ฌธ์ ์ฐธ๊ณ .
์๋ ์ฌ์ฉ์์ ํ๋กํ ์ ๋ณด์ ์ด๋ค ํ๋๊ฐ ์๋์ง ์ ์๋์ด ์๋ Profile
ํ์
์ด ์๋ค.
interface Profile {
id: number;
username: string;
email: string;
}
๋ง์ฝ ์ฌ์ฉ์ ํ๋กํ ์ ๋ณด๋ฅผ ์์ ํ๋ค๋ฉด ๊ฐ ํ๋๋ฅผ ๋ถ๋ถ์ ์ผ๋ก ์์ ํ๋๊ฒ ์ผ๋ฐ์ ์ด๋ค. ํ์ง๋ง ๊ธฐ์กด Profile
ํ์
์ ๋ชจ๋ ํ๋๊ฐ ํ์ ์์ฑ์ด๋ค. ๋๋ฌธ์ Profile
์ ๊ฐ ํ๋๋ฅผ ์ ํ์ ์์ฑ์ผ๋ก ๊ฐ์ง๋ ํ๋กํ ์ ๋ณด ์
๋ฐ์ดํธ ํ์
์ ๋ฐ๋ก ์ ์ํด์ผ ๋๋ค. ์ด๋ ๋งต๋ ํ์
์ ์ด์ฉํ๋ฉด ๊ธฐ์กด Profile
ํ์
์ ์ฌํ์ฉํ ์ ์๋ค.
type ProfileUpdate = {
[P in keyof Profile]?: Profile[P];
// [P in 'id' | 'username' | 'email']?... ์ ๋์ผ
};
๋งต๋ ํ์
์ผ๋ก ๊ตฌํ๋ ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์
์ธ Partial
์ ์ด์ฉํ๋ฉด ๋ ๊ฐ๊ฒฐํ๊ฒ ์์ฑํ ์ ์๋ค. Partial
์ ๋๊ฒจ ๋ฐ์ ํ์
์ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์ ํ์ (Optional)์ผ๋ก ์ค์ ํ ํ์
์ ์์ฑํ๋ค. ๋ฐ๋๋ก Required
๋ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ํ์๋ก ์ค์ ํ ํ์
์ ์์ฑํ๋ค.
type ProfileUpdate = Partial<Profile>;
// Partial ๋ด๋ถ ๊ตฌํ : type Partial<T> = { [P in keyof T]?: T[P] };
// ProfileUpdate : { id?: number, username?: string, email?: string }
๋ง์ฝ ๋งต๋ ํ์
์ ์ฌ์ฉํ์ง ์์๋ค๋ฉด Profile
ํ์
์ด ๊ฐ์ง๊ณ ์๋ ๊ฐ ํ๋๋ฅผ ์ค๋ณตํด์ ์์ฑํด์ผ ๋๋ค.
// ๋งต๋ ํ์
์ ์ฌ์ฉํ์ง ์์์ ๋ 1
interface ProfileUpdate {
id?: number;
username?: string;
email?: string;
}
// ๋งต๋ ํ์
์ ์ฌ์ฉํ์ง ์์์ ๋ 2
type ProfileUpdate = {
id?: Profile['id']; // number
username?: Profile['username']; // string
email?: Profile['email']; // string
};
์ฝ๊ธฐ์ ์ฉ ํ์ ์ผ๋ก ๋ณํ — Readonly
Readonly<Type>
๋งต๋ ํ์
์ ์ด์ฉํด ๊ธฐ์กด ํ์
(T
)์ ์ฝ๊ธฐ ์ ์ฉ(Readonly)์ผ๋ก ๋ง๋ค ์ ์๋ค. Readonly
ํ์
์ ํ์
์คํฌ๋ฆฝํธ์ ์ด๋ฏธ ๋ด์ฅ๋์ด ์์ผ๋ฏ๋ก(์ ํธ๋ฆฌํฐ ํ์
) ๋ฐ๋ก ์ ์ํ์ง ์๊ณ ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค.
interface Person {
name: string;
age: number;
}
type Readonly<T> = { readonly [P in keyof T]: T[P] }; // TS ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์
type T1 = Readonly<Person>;
// T1 : { readonly name: string, readonly age: number }
๊ฐ์ฒด ํ์ ์์ ์ผ๋ถ ์์ฑ๋ง ์ ํ — Pick
Pick<Type, Keys>
๐ก extends
ํค์๋๋ ์ธํฐํ์ด์ค / ํ์
์ ํ์ฅํ ๋ ์ฌ์ฉํ๋ค. ์๋ฅผ๋ค์ด K extends T
์ฝ๋๋ ์ ๋ค๋ฆญ K
๋ฅผ ์ ๋ค๋ฆญ T
์ ํ์ ํ์
์ผ๋ก ์ธ์ํ๋๋ก ํ๋ค. ๋ฐ๋ผ์ T
๊ฐ ๊ฐ์ง ์์ฑ์ K
๋ ๊ฐ์ง๊ฒ ๋๋ค.
๋งต๋ ํ์
์ ์ด์ฉํด ํน์ ํ์
(T
)์ ์ผ๋ถ ์์ฑ(K
)๋ง ์ ํํด์ ์๋ก์ด ํ์
์ผ๋ก ๋ง๋ค ์ ์๋ค. Pick
ํ์
์ญ์ ํ์
์คํฌ๋ฆฝํธ์ ์ด๋ฏธ ๋ด์ฅ๋์ด ์๋ ์ ํธ๋ฆฌํฐ ํ์
์ด๋ค.
interface Person {
name: string;
age: number;
language: string;
}
type Pick<T, K extends keyof T> = { [P in K]: T[P] }; // TS ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์
type T1 = Pick<Person, 'name' | 'age'>;
// T1 : {name: string, age: number}
์ ๋ค๋ฆญ T
์ Person
์ธํฐํ์ด์ค๋ฅผ ๋๊ธฐ๋ฏ๋ก keyof T
๋ 'name' | 'age' | 'language'
๊ฐ ๋๋ค. ๋๋ฌธ์ ์ ๋ค๋ฆญ K
์ ๋๊ธฐ๋ ๊ฐ์ keyof T
์ ์ผ๋ถ ํน์ ์ ๋ถ์ฌ์ผ ํ๋ค.
๐ก Pick
๊ณผ ๋ฐ๋๋ก ํน์ ํ์
์ ์ผ๋ถ ์์ฑ๋ง ์ ๊ฑฐํ ํ์
์ ์ ์ํ ์ ์๋ Omit
์ ํธ๋ฆฌํฐ ํ์
๋ ์๋ค. ์ฌ์ฉ๋ฒ์ Pick
๊ณผ ๋์ผํ๋ค.
์ ๋์จ ํ์ ์์ ํน์ ํ์ ๋ง ์ถ์ถ — Extract
Extract<Type, Union>
Extract<T, U>
์ ํธ๋ฆฌํฐ ํ์
์ T
ํ์
์์ U
์ ๋ช
์ํ ํ์
์ ์ถ์ถํ๋ค. Extract
๋ ์ฃผ๋ก ์ ๋์จ ํ์
์์ ํน์ ํ์
์ ์ถ์ถํ ๋ ์ฌ์ฉํ๋ค. U
์ ์ ๋์จ ํ์
์ ์ฌ์ฉํด ์ฌ๋ฌ ์์ฑ์ ํ ๋ฒ์ ์ถ์ถํ ์๋ ์๋ค.
type UserKey = 'name' | 'age' | 'address';
type UserName = Extract<UserKey, 'name'>; // 'name'
type UserNameAge = Extract<UserKey, 'name' | 'age'>; // 'name' | 'age'
๊ฐ์ฒด ํ์ ์์ ํน์ ์์ฑ ์ ์ธ — Omit
Omit<Type, Keys>
Omit<T, K>
์ ํธ๋ฆฌํฐ ํ์
์ T
ํ์
์์ K
์ ๋ช
์ํ ์์ฑ์ ์ ๊ฑฐํ ์๋ก์ด ํ์
์ ์์ฑํ๋ค. Omit
์ ์ฃผ๋ก ๊ฐ์ฒด ํ์
์์ ํน์ ์์ฑ์ ์ ์ธํ ๋ ์ฌ์ฉํ๋ค. K
์ ์ ๋์จ ํ์
์ ์ฌ์ฉํด ์ฌ๋ฌ ์์ฑ์ ์ ๊ฑฐํ ์๋ ์๋ค.
type User = { name: string; age: number; address: string };
type UserWithoutAddress = Omit<User, 'address'>;
// { name: string; age: number; }
type UserName = Omit<User, 'age' | 'address'>;
// { name: string; }
์ ๋์จ ํ์ ์์ ํน์ ํ์ ์ ์ธ — Exclude
Exclude<Type, ExcludedUnion>
Exclude<T, U>
์ ํธ๋ฆฌํฐ ํ์
์ T
ํ์
์์ U
์ ๋ช
์ํ ํ์
์ ์ ๊ฑฐํ ์๋ก์ด ์ ๋์จ ํ์
์ ์์ฑํ๋ค. Exclude
์ ์ฃผ๋ก ์ ๋์จ ํ์
์์ ํน์ ํ์
์ ์ ์ธํ ๋ ์ฌ์ฉํ๋ค. U
์ ์ ๋์จ ํ์
์ ์ฌ์ฉํด ์ฌ๋ฌ ์์ฑ์ ์ ๊ฑฐํ ์๋ ์๋ค.
type UserKey = 'name' | 'age' | 'address';
type UserKeyWithoutAddress = Exclude<UserKey, 'address'>; // 'name' | 'age'
type UserName = Exclude<UserKey, 'address' | 'age'>; // 'name'
์์ฑ๊ฐ์ ๋ค๋ฅธ ํ์ ์ผ๋ก ์ง์ — Record
Record<Keys, Type>
๋งต๋ ํ์
์ ์ด์ฉํด ํน์ ์์ฑ(K
)์ ๊ฐ์ด ๋ค๋ฅธ ํ์
(T
)์ผ๋ก ์ง์ ๋ ํ์
์ ๋ง๋ค ์ ์๋ค. Record
ํ์
์ญ์ ํ์
์คํฌ๋ฆฝํธ์ ์ด๋ฏธ ๋ด์ฅ๋์ด ์๋ ์ ํธ๋ฆฌํฐ ํ์
์ด๋ค. [P in K]: T
์ฝ๋๋ฅผ ํตํด K
์์ฑ('Smith' | 'John'
)์ผ๋ก ๊ตฌ์ฑ๋ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค๊ณ , K
์์ฑ ๊ฐ์ ํ์
์ T
(Person
ํ์
)๊ฐ ๋๋ค.
interface Person {
name: string;
age: number;
}
type Record<K extends keyof any, T> = { [P in K]: T }; // TS ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์
type T1 = Record<'Smith' | 'John', Person>;
// T1 : {Smith: Person, John: Person}
// Smith, John ์์ฑ์ ๊ฐ์ Person ์ธํฐํ์ด์ค ๊ตฌ์กฐ์ ๊ฐ์ฒด์ฌ์ผ ํจ
๊ฐ์ฒด ์์ฑ์ ์ ํ์ ์ผ๋ก ๋ณ๊ฒฝ — Optional
Optional<Type, Keys>
Optional
์ T
ํ์
์์ K
ํ๋กํผํฐ๋ฅผ ์ ํ์ ์ผ๋ก ๋ง๋๋ ์ปค์คํ
์ ํธ๋ฆฌํฐ ํ์
์ด๋ค. ๋จผ์ , โ ์ ๋ค๋ฆญ์ผ๋ก ๋ฐ์ K
ํ๋กํผํฐ๋ฅผ ์ ์ธํ ํ์
์ ์์ฑํ๊ณ (Omit<T, K>
), โก์ ์ธํ์ง ์์ ๋๋จธ์ง(Pick<T, K>
) ํ๋กํผํฐ๋ฅผ โข์ ํ์ ์ผ๋ก ๋ง๋ ํ(Partial
) โฃ์ด ๋ ํ์
์ &
์ฐ์ฐ์๋ก ๋ค์ ํฉ์น๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ๋๋ค. Optional
์ ํ์
์คํฌ๋ฆฝํธ์์ ์ ๊ณตํ์ง ์๋ ์ปค์คํ
์ ํธ๋ฆฌํฐ ํ์
์ด๋ค.
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
// K -> 'age'
// Omit<T, K> -> { name: string }
// Pick<T, K> -> { age: number }
// Partial<...> -> { age?: number }
type Person = { name: string, age: number };
type OnlyName = Optional<Person, 'age'> // { name: string, age?: number }
Enum ์ด๋ ํ์ฉ
๐ก ์ด๋์ ๋ณธ์ง์ ์ผ๋ก ๊ฐ์ฒด์ด๋ฏ๋ก ๋ฐํ์์์ ๊ฐ์ฒด๋ก ๋์ํ๋ค. ๋ฐ๋ฉด, ํ์ ์คํฌ๋ฆฝํธ(ํ์ ๋ฌธ๋งฅ)์์ ์ด๋์ ๋ชจ๋ ๋ฉค๋ฒ ๊ฐ์ ์ ๋์จ ํ์ ์ผ๋ก ์ทจ๊ธํ๋ค.
์ด๋์ ๋ช ํํ ์๋ฏธ๋ฅผ ์ง๋ ์์ ๊ฐ์ ๊ทธ๋ฃนํํ์ฌ ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์์ ์ฑ์ ๋์ฌ์ค๋ค. ๋ํ ํ์ / ๊ฐ ๋ชจ๋ ํ์ฉํ ์ ์์ด์ ํจ์จ์ ์ธ ์ฝ๋ ์์ฑ์ ์ ์ฉํ๋ค.
์ค์ ๋ฐฉ์ง
์ค๋งํธํฐ ๋ธ๋๋ ๋ฆฌ์คํธ๋ฅผ ๋์ดํ Brands
์ด๋ ํ์
์ด ์๊ณ , ์ด๋ ํ์
์ ์๋ ๋ชจ๋ ๋ธ๋๋์ ๊ฐ๊ฒฉ์ (๊ฐ์ฒด ํ์์ผ๋ก)์ ์ํด์ผ ๋๋ค๊ณ ๊ฐ์ ํด๋ณธ๋ค.
enum Brands {
APPLE, // 0
OPPO, // 1
XIAOMI, // 2
}
๊ฐ ๋ธ๋๋์ ๊ฐ๊ฒฉ์ ํ์ํ๊ธฐ ์ํด Brands
์ด๋ ํ์
์ ์ฐธ์กฐํ์ฌ BRAND_PRICE
๊ฐ์ฒด๋ฅผ ์ ์ํ๋ค. ์ค์๋ก ์ค์ค๋ฏธ ๋ธ๋๋๊ฐ(Brands.XIAOMI
) ๋๋ฝ๋์ง๋ง ๋ฐ๋ก ํ์
์ ์ง์ ํ์ง ์์์ผ๋ฏ๋ก ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. ๋ง์ฝ Brands
์ด๋ ํ์
์ ๋์ด๋ ๋ชจ๋ ๋ธ๋๋์ ๊ฐ๊ฒฉ์ ๋ช
์ํ๋๋ก ๊ฐ์ ํ๊ณ ์ถ๋ค๋ฉด?
const BRAND_PRICE = {
[Brands.APPLE]: 100_000_000,
[Brands.OPPO]: 80_000_000,
// Brands.XIAOMI ์์ฑ ๋๋ฝ
};
BRAND_PRICE
๊ฐ์ฒด์ ํ์
์ [key in Brands]...
๋งต๋ ํ์
์ผ๋ก ์ง์ ํ๋ฉด ๋๋ค. ๊ทธ๋ผ Brands
์ด๋ ํ์
์ ๋ชจ๋ ์์ฑ์ ์ ์ํด์ผ๋ง ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. ์๋ ์ฝ๋์์ Brands.XIAOMI
์์ฑ์ด ๋๋ฝ๋์ผ๋ฏ๋ก ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ์ด์ฒ๋ผ ๋งต๋ ํ์
์ ์ด์ฉํ๋ฉด ๊ฐ์ฒด์ ํน์ ์์ฑ์ด ๋๋ฝ๋๋ ์ค์๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
// Error! XIAOMI ์์ฑ์ด ์์ผ๋ฏ๋ก ์๋ฌ ๋ฐ์
const BRAND_PRICE: { [key in Brands]: number } = {
[Brands.APPLE]: 100_000_000,
[Brands.OPPO]: 80_000_000,
// Brands.XIAOMI ์์ฑ ๋๋ฝ
};
์ด๋ ํน์ง
์ด๋ ๋ฉค๋ฒ์ ๊ฐ์ ๋ช ์์ ์ผ๋ก ์ง์ ํ์ง ์์ผ๋ฉด 0๋ถํฐ ์ฆ๊ฐํ๋ ์ซ์๋ฅผ ์๋์ผ๋ก ํ ๋นํ๋ค. ์ซ์ ๊ธฐ๋ฐ์ ์ด๋์ ๋ฐํ์ ๋ key / value ์ ๋ณด๋ฅผ ๋ชจ๋ ์ ์ฅํ๋ค. ๋ฐ๋ผ์ key / value(์ซ์)๋ฅผ ์ฌ์ฉํด์ ์ ๊ทผํ ์ ์๋ค.
enum Brands {
APPLE, // 0
OPPO, // 1
XIAOMI, // 2
}
console.log(Brands); // { '0': 'APPLE', '1': 'OPPO', '2': 'XIAOMI', APPLE: 0, OPPO: 1, XIAOMI: 2 }
console.log(Object.keys(Brands)); // ['0', '1', '2', 'APPLE', 'OPPO', 'XIAOMI']
console.log(Object.values(Brands)); // ['APPLE', 'OPPO', 'XIAOMI', 0, 1, 2]
console.log(Brands[0]); // 'APPLE'
console.log(Brands.APPLE); // 0
์ด๋ ๊ฐ ๋ฉค๋ฒ์ ๋ฌธ์์ด ๊ฐ์ ํ ๋นํ๋ฉด ๋ฐํ์์์ ํด๋น ๋ฌธ์์ด ๊ฐ๋ง ๊ฐ์ง๋ค. ์ซ์ ์ด๋์ฒ๋ผ key / value ๊ฐ์ ์ด์ค์ผ๋ก ์ ์ฅํ์ง ์๋๋ค.
enum Brands {
APPLE = '์ ํ',
OPPO = '์คํฌ',
XIAOMI = '์ค์ค๋ฏธ',
}
console.log(Brands); // { APPLE: '์ ํ', OPPO: '์คํฌ', XIAOMI: '์ค์ค๋ฏธ' }
console.log(Object.keys(Brands)); // ['APPLE', 'OPPO', 'XIAOMI']
console.log(Object.values(Brands)); // ['์ ํ', '์คํฌ', '์ค์ค๋ฏธ']
console.log(Brands.APPLE); // '์ ํ'
console.log(Brands[0]); // Error! TS7053: ...
ํ์
์คํฌ๋ฆฝํธ(ํ์
๋ฌธ๋งฅ)์์ ์ด๋์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ๋ฉค๋ฒ ๊ฐ์ ์ ๋์จ ํ์
์ผ๋ก ์ทจ๊ธํ๋ค. ๋ฐ๋ผ์ Record
key ์ฌ๋กฏ์ ์ฌ์ฉํ Colors
ํ์
์ '๋นจ๊ฐ'|'ํ๋'|'๋
น์'
์ด ๋๋ค.
enum Colors {
RED = '๋นจ๊ฐ',
BLUE = 'ํ๋',
GREEN = '๋
น์',
}
type ColorType = Record<Colors, number>;
// { ๋นจ๊ฐ: number, ํ๋: number, ๋
น์: number }
๋ณ์, ํจ์ ํ๋ผ๋ฏธํฐ ๋ฑ์ ํ์ ์ ๋ฌธ์์ด ์ด๋์ผ๋ก ์ง์ ํ๋ฉด ํด๋น ์ด๋์ ๋ฉค๋ฒ๋ง ํ์ฉํ๋ค. ์ฆ, ์ด๋ ๋ฉค๋ฒ์ ๊ฐ์ด ๋ฌธ์์ด์ผ ๋ ์ด๋ ๋ฉค๋ฒ๊ฐ ์๋ ์ผ๋ฐ ๋ฌธ์์ด์ ์ฌ์ฉํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค(์ซ์ํ ์ด๋์์ ์ผ๋ฐ ์ซ์๋ ๊ฐ๋ฅ).
enum Colors {
RED = '๋นจ๊ฐ',
BLUE = 'ํ๋',
GREEN = '๋
น์',
}
// ํ๋ผ๋ฏธํฐ ํ์
: Colors.RED | Colors.BLUE | Colors.GREEN
function paintWall(color: Colors) {
console.log(`Painting the wall with ${color} color.`);
}
paintWall(Colors.RED); // 'Painting the wall with ๋นจ๊ฐ color.'
paintWall('RED'); // Error! TS2345: Argument of type 'RED' is not assignable ...
๋ฒ์ธ — ๊ฐ์ฒด์ Key / Value๋ก ๊ตฌ์ฑ๋ ํ์ ๋ง๋ค๊ธฐ
์๋ ๊ฐ ์ด๋ฆ(fox
, chick
, ...)์ ํด๋นํ๋ ์์๊ฐ์ ๋ํ๋ด๋ colors
๊ฐ์ฒด๊ฐ ์๋ค.
const colors = {
fox: '#FFC7CC',
chick: '#FFD784',
alien: '#B2E9E3',
devil: '#E1BCEA',
} as const; // ๊ฐ์ฒด์ ํ ๋น๋ ๋ฆฌํฐ๋ด ๊ฐ์ผ๋ก ํ๋กํผํฐ ํ์
์ถ๋ก
๋งต๋ ํ์
๊ณผ keyof
ํค์๋๋ฅผ ์ด์ฉํด ๊ฐ์ฒด์ value
๋ง ์ถ์ถํด์ ํ์
์ผ๋ก ๋ง๋ค ์ ์๋ค. ๊ฐ์ฒด key
๋ ์ ํธ๋ฆฌํฐ ํ์
์์ด keyof typeof ๊ฐ์ฒด
์ฝ๋๋ก ๋ฐ๋ก ์ถ์ถํ ์ ์๋ค.
type ValueOf<T> = T[keyof T]; // T๋ก ๋ฐ์ ๊ฐ์ฒด์ ๋ชจ๋ ๊ฐ์ ์ ๋์จ ํ์
์ผ๋ก ๋์ด
// key๋ง ์ถ์ถํด์ ํ์
์ผ๋ก ์ค์ / Object.keys ๋ฐํ๊ฐ์ ์ฌ์ฉ
type ColorKey = keyof typeof colors; // 'fox' | 'chick' | 'alien' | 'devil'
// value๋ง ์ถ์ถํด์ ํ์
์ผ๋ก ์ค์ / Object.values ๋ฐํ๊ฐ์ ์ฌ์ฉ
type ColorValue = ValueOf<typeof colors>; // '#FFC7CC' | '#FFD784' | '#B2E9E3' | '#E1BCEA'
// ์ถ์ถํ key/value๋ฅผ tuple ํ์
์ผ๋ก ์ค์ / Object.entries ๋ฐํ๊ฐ์ ์ฌ์ฉ
type ColorEntries = Array<[ColorKey, ColorValue]>;
Object.keys|values
๋ ํ์
์ถ๋ก ์ ํตํด ๋ฐ๋ก ํ์
์ ์ง์ ํ์ง ์์๋ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ๋ฐ๋ฉด ํ์
์ถ๋ก ์ด ์ ์๋๋ Object.entries
๋ ์๋์ฒ๋ผ ์ ํธ๋ฆฌํฐ ํ์
์ผ๋ก ๋ง๋ค์ด๋๊ณ ์ฐ๋ฉด ํธํ๋ค.
// ์ฝ๋ ์ฐธ๊ณ StackOverFlow
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
const colorEntries = Object.entries(colors) as Entries<typeof colors>;
Entries
์ ๋๊ธด ํ์
์ด { a: number, b: string }
์ด๋ผ๊ณ ๊ฐ์ ํด๋ณด์. ๋จผ์ ๊ฐ ํค์, ํด๋น ํค์ ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋ ํํ์ ์์ฑํ๊ณ , ์ด๋ฅผ ๋งต๋ ํ์
์ผ๋ก ๊ตฌ์ฑํ๋ค.
// { [K in keyof T]: [K, T[K]] } ๋ถ๋ถ์์ ์์ฑํ ํ์
{
a: ['a', number];
b: ['b', string];
}
์์ฑํ ๋งต๋ ํ์ ์ ์ธ๋ฑ์ฑํ์ฌ ๊ฐ ํค์ ๋์ํ๋ ํํ ํ์ ์ ์ฐธ์กฐํ๊ณ , ๋ชจ๋ ํค(a, b)์ ๋ํ ํํ์ ์ ๋์จ ํ์ ์ผ๋ก ๊ฒฐํฉํ๋ค.
// [keyof T] ๋ถ๋ถ์์ ์์ฑํ ํ์
['a', number] | ['b', string];
๋ง์ง๋ง์ผ๋ก ์ด ์ ๋์จ ํ์ ์ ์์๋ค์ ๋ชจ๋ ํฌํจํ ์ ์๋ ๋ฐฐ์ด ํ์ ์ ์์ฑํ๋ค.
// [] ๋ถ๋ถ์์ ์์ฑํ ํ์
(['a', number] | ['b', string])[]
๋ ํผ๋ฐ์ค
- ๋งต๋ ํ์ | ํ์ ์คํฌ๋ฆฝํธ ํธ๋๋ถ
- [TypeScript] ๋งต๋ ํ์
- Typescript ์ ํธ๋ฆฌํฐ ํด๋์ค ํํค์น๊ธฐ
- Documentation - Utility Types
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] ๋ฆฌ์กํธ ๋๋๊ทธ์ค๋๋กญ ํ์ผ ์ ๋ก๋ ๊ตฌํ (0) | 2024.05.05 |
---|---|
[HTML/CSS] width ์์ฑ ์๋ ๋งค์ปค๋์ฆ (0) | 2024.05.05 |
[TS] ํ์ ์คํฌ๋ฆฝํธ - ํ์ ํธํ (0) | 2024.05.04 |
[DevTools] ์ธ๋ถ์์ ๋ก์ปฌ ์๋ฒ ์ ์ํ๊ธฐ โ ngrok (0) | 2024.05.04 |
[React] Blur ํจ๊ณผ๋ฅผ ํ์ฉํ ์ด๋ฏธ์ง ์ง์ฐ ๋ก๋ฉ Image Lazy Loading (0) | 2024.05.04 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[React] ๋ฆฌ์กํธ ๋๋๊ทธ์ค๋๋กญ ํ์ผ ์ ๋ก๋ ๊ตฌํ
[React] ๋ฆฌ์กํธ ๋๋๊ทธ์ค๋๋กญ ํ์ผ ์ ๋ก๋ ๊ตฌํ
2024.05.05 -
[HTML/CSS] width ์์ฑ ์๋ ๋งค์ปค๋์ฆ
[HTML/CSS] width ์์ฑ ์๋ ๋งค์ปค๋์ฆ
2024.05.05 -
[TS] ํ์ ์คํฌ๋ฆฝํธ - ํ์ ํธํ
[TS] ํ์ ์คํฌ๋ฆฝํธ - ํ์ ํธํ
2024.05.04 -
[DevTools] ์ธ๋ถ์์ ๋ก์ปฌ ์๋ฒ ์ ์ํ๊ธฐ — ngrok
[DevTools] ์ธ๋ถ์์ ๋ก์ปฌ ์๋ฒ ์ ์ํ๊ธฐ — ngrok
2024.05.04