β μ’μ νλ‘κ·Έλλ¨Έ λλΆλΆμ λμ΄λ λμ€μκ² λ°μ μ°¬μ¬λ₯Ό κΈ°λνκ³ νλ‘κ·Έλλ°μ νμ§ μκ³ νλ‘κ·Έλλ°μ΄ μ¬λ―Έ μμ΄μ νλ€. β
- Linus Torvalds
리λ μ€ μ°½μμ

νμ μ€ν¬λ¦½νΈ 맡λ νμ
νμ μ€ν¬λ¦½νΈμ κ³ κΈ νμ μΈ λ§΅λ νμ (mapped type)μ΄λ κΈ°μ‘΄μ μ μλμ΄ μλ νμ μ μλ‘μ΄ νμ μΌλ‘ λ³νν΄ μ£Όλ λ¬Έλ²μ μλ―Έ νλ€.
μλ₯Ό λ€μ΄ μΈν°νμ΄μ€μ μλ λͺ¨λ μμ±μ 루νλ¬Έ κ°μ΄ μνν΄μ optional(?) λ‘ λ°κΎΈκ±°λ readonly λ‘ μ§μ ν μ μμΌλ©°, μμ μ§μ λ νμ μ λ°κΏμ λ³κ²½λ νμ μ λ°νν μ λ μλ€.

μμ§ λ§΅λ νμ μ λν΄ λ¬Έλ²μ λ°°μ°μ§λ μμμ§λ§ κ°λ¨νκ² μ΄ν΄λ³΄μλ©΄ λ€μκ³Ό κ°λ€.
interface Obj {
prop1: string;
prop2: string;
}
type ChangeType<T> = {
[K in keyof T]: number;
};
type Result = ChangeType<Obj>;
/*
{
prop1: number;
prop2: number;
}
*/
Obj λΌλ μΈν°νμ΄μ€μ κ°μ²΄ μμ± νμ
stringμ ChangeType<Obj> μ ν΅ν΄ Obj νμ
λ€μ numberλ‘ λͺ¨λ λ°κΏμ£Όκ³ Result νμ
λ³μΉμκ² λ°ννμλ€.
κ·Έλμ κ²°κ³Όμ μΌλ‘ νμ
Resultλ { prop1: number; prop2; number } μ κ°μ κ°μ²΄ νμ
μ κ°μ§κ² λμλ€.
μ΄λ λ§μΉ μλ°μ€ν¬λ¦½νΈλ‘ λ°μ§λ©΄, κ°μ²΄μ μμ±μ valueλ₯Ό ν¨μμμ for in μΌλ‘ κ°μ²΄λ₯Ό μνν΄ κ° μμ±μ κ°λ€μ λ¬Έμμ΄μμ μ«μλ‘ λ°κΏμ£Όλ κ²κ³Ό λΉμ·ν΄ 보μΈλ€.
const Obj = {
prop1: "νκΈΈλ",
prop2: "νκΈΈλ"
}
function ChangeValue(T) {
for(let K in T) { T[K] = 1000; }
return T;
}
const Result = ChangeValue(Obj);
/*
{
prop1: 1000,
prop2: 1000
}
*/
νμ μ€ν¬λ¦½νΈλ νμ μ λ°λ‘ λ€λ£¨λ μΈμ΄μ΄λ, μμ λ‘μ§μμ valueκ° μλλΌ typeμΌλ‘ λ°κΏ μκ°ν΄λ³΄λ©΄ νλ°μ΄λΌκ³ 보면 λλ€.
맡λ νμ λ¬Έλ²

μ΄μ²λΌ 맡λ νμ μ κ°μ²΄μ μμ±λ€μ μνν΄μ μμ±μ νμ μ λ€λ₯Έ νμ μΌλ‘ λ°κΏμ£Όλ μν μ νλ€.
κ°μ²΄ νμ μ μμ±λ€μ μννκΈ° λλ¬Έμ μ΄λ₯Ό μμ©ν΄μ, λͺ¨λ κ°μ²΄μ μμ±λ€μ μνν΄μ optional(?) λ‘ λ°κΎΈκ±°λ readonly λ‘ μ§μ ν μλ μλ€.
κΈ°μ‘΄μλ μ΄λ κ² μΈν°νμ΄μ€λ‘ μΌμΌν λ°λ‘λ°λ‘ μ§μ νλκ±Έ,
interface PersonPartial {
name?: string;
age?: number;
}
interface PersonReadonly {
readonly name: string;
readonly age: number;
}
맡λ νμ λ¬Έλ²μ μ΄μ©ν΄μ λ§μΉ ν¨μλ₯Ό μ΄μ©νλ κ²μ²λΌ μμ±λ€μ μνν΄μ λ³κ²½ν΄μ£Όκ³ κ·Έ κ²°κ³Όκ°μ type aliasμκ² λ³νν΄ μ€λ€. λ³΄λ€ μνΌ λ§΅λ νμ μ μ λ€λ¦κ³Ό κ²°ν©νλ©΄ 맀μ°λ§€μ° κ°λ ₯ν΄μ§λ€.
interface Person {
name: string;
age: number;
}
type ReadOnly<T> = {
readonly [P in keyof T]: T[P];
};
type ParTial<T> = {
[P in keyof T]?: T[P];
};
type PersonPartial = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;

μ΄μ 맡λ νμ μ΄λΌλ κΈ°λ₯μ λν΄ μ΅μν΄μ‘μΌλ, 맡λ νμ κ΅¬μ± λ¬Έλ²μ λν΄ μ°¨κ·Όμ°¨κ·Ό μμ보μ.
interface Obj {
name: string;
email: string;
}
type ObjNumber = {
[P in keyof Obj]: number // 맡λ νμ
};
/*
type ObjNumber = {
name: number;
email: number;
}
*/
μ μ½λμμ 보λ€μνΌ, 맡λ νμ μ λ§λ€μ΄μ§λ λ°ν κ°μ΄ κ°μ²΄ νμ ννμ΄κΈ° λλ¬Έμ μ€κ΄νΈλ‘ λλ¬μμ¬μ Έ μμΌλ©°, μ€κ΄νΈ μμ λκ΄νΈλ ν€ λΆλΆμ λνλΈλ€.
λ§μΉ μΈν°νμ΄μ€μ indexable νμ μ μκ°νλ©΄ λλ€.

κ·Έλ°λ° μΈν°νμ΄μ€μ indexable νμ κ³Ό λ€λ₯Έμ μ΄ μλλ° λ°λ‘ λκ΄νΈ μμ in ν€μλλ₯Ό μ¬μ©νλ€λ μ μ΄λ€.
in μ°μ°μλ μλ°μ€ν¬λ¦½νΈμ for in μΌλ‘ μκ°νλ©΄ νΈνλ€.
for in μ κ°μ²΄μ keyλ₯Ό μννλ 루νλ¬ΈμΈλ° μ΄ μν μ λκ°μ΄ λ°λΌνλ€κ³ 보면 λλ€.
κ·Έλ¦¬κ³ λκ΄νΈ μμ keyμ λͺ
μΉμ indexable νμ
μ΄λ μ λ€λ¦ κ°μ΄ λ§μλλ‘ μ§μ΄λλλ€. for in μΌλ‘ λ°μ§λ©΄ for (let i in obj) μμμ λ³μ i μ κ°μ κ°λ
μ΄λ€. (inμΌλ‘ μννλ κ°λ€μ μ μ₯νλ μμ λ³μ)
λ§μ§λ§μΌλ‘ keyof λ μΈν°νμ΄μ€ Objμ κ°μ²΄ νμ
μμ±λ€μ λ½μ μ λμ¨μΌλ‘ name | email λ§λ€μ΄μ£Όλ μν μ νλ€. (μ°Έκ³ κΈ)
맡λ νμ νμ© μμ
맡λ νμ μ κ·Έμ λ μ¬λ¦¬λ κ²λ³΄λ¨, μ€μ μμ μ½λλ₯Ό ν΅ν΄ μ΅νλ κ²μ΄ μ’λ€.
λ€μ μμ μ½λλ€μ 보며 λ¨Έλ¦Ώμμ μ΅ν보μ.
맡λ νμ μΌλ‘ κ°μ²΄ νμ μμ±
μ λμ¨μΌλ‘ μμ±λͺ λ€μ μ§μ ν΄μ£Όκ³ in ν€μλλ‘ μνν΄ μ£Όλ©΄μ μ§μ ν μλͺ λ€μ νμ μ boolean μ΄λ number λ‘ μ§μ νκ³ , μμ±λ νμ μ νμ λ³μΉμ λ°ννλ μμ μ΄λ€.
type T1 = {
[K in "prop1" | "prop2"]: boolean
};
/*
type T1 = {
prop1: boolean;
prop2: boolean;
}
*/
type T2 = {
[K in "prop1" | "prop2"]: number
};
/*
type T2 = {
prop1: number;
prop2: number;
}
*/
type T3 = {
[K in "prop1" | "prop2"]: string
};
/*
type T3 = {
prop1: string;
prop2: string;
}
*/
맡λ νμ μ μ λ€λ¦κ³Ό κ²°ν©ν΄μ μ¬μ©νλ©΄ λ§μΉ μλ°μ€ν¬λ¦½νΈ ν¨μ μ²λΌ νμ μ λ§λ€κ³ λ°ννλ λ‘μ§μ κ΅¬μ± ν μ μλ€.
type Prop = 'prop1' | 'prop2';
type Make<T> = {
[K in Prop]: T
};
type T1 = Make<boolean>;
/*
type T1 = {
prop1: boolean;
prop2: boolean;
}
*/
type T2 = Make<number>;
/*
type T2 = {
prop1: number;
prop2: number;
}
*/
type T3 = Make<string>;
/*
type T3 = {
prop1: string;
prop2: string;
}
*/
μ΄λ κ² λ§λ€μ΄μ§ νμ μΌλ‘ κ°μ²΄ λ³μλ₯Ό μ μΈνμ¬ μ΄μ©νλ©΄ λλ€.
const obj1: T1 = {
prop1: true,
prop2: false,
};
const obj2: T2 = {
prop1: 123,
prop2: 66666,
};
const obj3: T3 = {
prop1: 'hello',
prop2: 'world',
};
맡λ νμ μΌλ‘ κ°μ²΄ μμ± μ κ±°
μλμ κ°μ΄ μ¬μ©μ νλ‘νμ μ‘°ννμ¬ κ°μ²΄λ₯Ό λ°ννλ API ν¨μκ° μλ€κ³ κ°μ νλ€.
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
// λ§μ½ apiλ₯Ό μμ²ν΄ μ μ νλ‘νμΌμ μλ΅νλ http ν¨μλΌκ³ κ°μ νλ€λ©΄
function fetchUserProfile(): UserProfile {
return {
username: 'νκΈΈλ',
email: 'hongildong@naver.com',
profilePhotoUrl: 'image',
};
}
const user: UserProfileUpdate = fetchUserProfile();
λ§μΌ μ¬μ©μκ° μΉμμ νλ‘ν μ 보λ₯Ό μμ νλ€λ©΄, μ΄ νλ‘ν κ°μ²΄μ μ 보λ₯Ό μμ νλ APIλ UserProfileUpdate λΌκ³ κ°μ νμ.
μ¬κΈ°μ optional ν€μλλ§ λΆμΈ λκ°μ ννμ μΈν°νμ΄μ€λ₯Ό μμ±νλ μ΄μ λ, κΈ°μ‘΄μ UserProfile μΈν°νμ΄μ€ νμ μ κ°νκ² νμ μ΄ μ ν΄μ ΈμκΈ° λλ¬Έμ, κ°μ²΄μ μμ±μ μμ νκΈ° μν΄μλ μ΄λ°μμ μ‘°μΉλ₯Ό μ·¨ν΄ μ£Όμ΄μΌ νλ€.
interface UserProfileUpdate {
username?: string;
email?: string;
profilePhotoUrl?: string;
}
// μ¬μ©μκ° μμ μ νλ‘ν μ΄λ―Έμ§λ₯Ό μμ μ²λ¦¬λ₯Ό νμ¬, μ μ κ°μ²΄μμ νλ‘νμΌ μ΄λ―Έμ§ url μμ±μ μμ ν΄μ μ
λ°μ΄νΈνλ api
function updateUserProfile(params: UserProfileUpdate) {
delete params.profilePhotoUrl;
}
updateUserProfile(user);
νμ§λ§ κ°μ λͺ¨μμ μΈν°νμ΄μ€λ₯Ό λ°λ³΅ν΄μ μ μΈνλ κ²μ κ°λ μ±μ λ§€μ° μμ’μΌλ νΌν΄μΌ νλ€.
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
interface UserProfileUpdate {
username?: string;
email?: string;
profilePhotoUrl?: string;
}
κ·Έλμ μμ μΈν°νμ΄μ€μμ λ°λ³΅λλ ꡬ쑰λ₯Ό μλμ κ°μ λ°©μμΌλ‘ μ¬νμ© ν μ μλ€.
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
type UserProfileUpdate = {
[p in 'username' | 'email' | 'profilePhotoUrl']?: UserProfile[p];
};
/*
type UserProfileUpdate = {
username?: string | undefined;
email?: string | undefined;
profilePhotoUrl?: string | undefined;
}
*/
μ¬κΈ°μ μ μ½λμ keyof μΈν°νμ΄μ€ λ₯Ό μ μ©νλ©΄, μλμΌλ‘ κ°μ²΄ μμ±λ€μ λͺ¨μ μ λμ¨ νμ
μΌλ‘ λ³νν΄μ€μ, μλμ κ°μ΄ μ€μΌ μ μλ€.
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
type UserProfileUpdate = {
[p in keyof UserProfile]?: UserProfile[p];
};
μΈν°νμ΄μ€ νμ λ°κΎΈκΈ°
interface Person {
name: string;
age: number;
}
type MakeBoolean<T> = {
[P in keyof T]?: boolean
};
const pMap: MakeBoolean<Person> = {}; // Person μΈν°νμ΄μ€μ νμ
λ€μ λͺ¨λ booleanμΌλ‘ λ³κ²½νκ³ optionalλ‘ μ§μ
/*
{
name?: boolean | undefiened;
age?: boolean | undefiened;
}
*/
pMap.name = true;
pMap.age = false;
pMap.age = undefined; // μ ν μμ±μ΄κΈ°μ undefiened ν λΉ κ°λ₯
readonly / optional λΆμ΄κΈ°
μμμ νλ² μκ°ν 맡λ νμ μ λνμ μΈ κΈ°λ²μ΄λ€.
κ·Έλ°λ° μ¬κΈ°μ μ£Όμ κΉκ² λ΄μΌ ν μ μ T[P] λΆλΆμΈλ°, μ΄ ν€μλμ μλ―Έλ μ λ€λ¦μΌλ‘ λ°μ μμ±μ νμ
μ μ μ§νλ€ λΌλ μλ―Έμ΄λ€.
μλ₯Ό λ€μ΄ Partial<Person> 맡λ νμ
μ νΈμΆνλ©΄, μ λ€λ¦ Tμ Personμ΄ λ€μ΄μ¬κΊΌκ³ , 맡λ νμ
Pμ Personμ keyofμΈ (name | age) μ λμ¨ νμ
μ΄ μνλμ΄ νλμ© Pμ λ€μ΄μ€κ² λλ€.
κ²°κ΅ T[P] λ Person[name] κ³Ό Person[age] κ° λ κ²μ΄κ³ , μ΄λ 곧 μμ± μκΈ° μμ μ νμ
λ°Έλ₯λ₯Ό κ°λ¦¬ν€λ κ²μ΄λ, μμ μ μμ±μ νμ
μ 볡μ¬ν΄ κ·Έλλ‘ λ°ννλ€λ μλ―Έμ΄λ€.
interface Person {
name: string;
age: number;
}
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type PersonPartial = Partial<Person>;
/*
type PersonPartial = {
name?: string | undefined;
age?: number | undefined;
}
*/
type ReadonlyPerson = Readonly<Person>;
/*
type ReadonlyPerson = {
readonly name: string;
readonly age: number;
}
*/
readonly / optional λΌλ²λ¦¬κΈ°
μμ±λ€μ μνν΄μ readonly μ ? λ₯Ό λΆμ¬λ΄€μΌλ©΄ μ΄λ²μ μ κ±°ν΄λ³΄λ 맡λ νμ μ λ§λ€μ΄ 보μ.
μ¬κΈ°μ μλ‘μ΄ μ°μ°μκ° λμ€λλ° λ°λ‘ λ§μ΄λμ€ - μ°μ°μμ΄λ€. μ΄λ ΅κ² μ΄ν΄ν νμμμ΄ μ κ±°μ μλ―Έλ₯Ό λ΄ν¬νλ€.
interface Person1 {
name?: string;
age?: number;
}
interface Person2 {
readonly name: string;
readonly age: number;
}
type Exclude_ReadOnly<T> = {
// -readonly λΌλ λ»μ readonlyλ₯Ό λΌλΌ λΌλ μλ―Έμ΄λ€.
// λ°λλ‘ +readonly λ readonlyλ₯Ό μΆκ°νλΌλ μλ―ΈμΈλ° μ μλ₯Ό +1λ‘ μμ°λ―μ΄ κ·Έλ₯ μλ΅ κ°λ₯ν¨
-readonly [P in keyof T]: T[P];
};
type Exclude_ParTial<T> = {
// -? λΌλ λ»μ ?λ₯Ό λΌλΌ λΌλ μλ―Έμ΄λ€.
// λ°λλ‘ +? λ ?λ₯Ό μΆκ°νλΌλ μλ―ΈμΈλ° μ μλ₯Ό +1λ‘ μμ°λ―μ΄ κ·Έλ₯ μλ΅ κ°λ₯ν¨
[P in keyof T]-?: T[P];
};
type PersonPartial = Exclude_ParTial<Person1>;
/*
type PersonPartial = {
name: string;
age: number;
}
*/
type ReadonlyPerson = Exclude_ReadOnly<Person2>;
/*
type ReadonlyPerson = {
name: string;
age: number;
}
*/
μ€μ²© κ°μ²΄ μμ± λ§λ€κΈ°
맡λ νμ μ μ΄μ©ν΄ μ€μ²© κ°μ²΄ μμ± νμ μ μ΄λ£¨λ μμ μ΄λ€.
/* eslint-disable */
export {};
interface Person {
name: string;
age: number;
language: string;
}
type Recorded<K extends string, T> = { [P in K]: T };
type T1 = Recorded<'p1' | 'p2', Person>;
const t: T1 = {
p1: {
name: 'νκΈΈλ',
age: 88,
language: 'kor',
},
p2: {
name: 'λ§μ»¨',
age: 34,
language: 'eng',
},
};
맡λ νμ μ μ λ©€λ² μΆκ°
λ©€λ²λ₯Ό μΆκ°νκΈΈ μνλ€λ©΄, κ΅μ°¨ νμ μ μ΄μ©ν΄ ꡬμ±ν μ μλ€
interface Person {
name: string;
age: number;
}
type PartialWithNewMember<T> = {
[P in keyof T]?: T[P];
} & { newMember: boolean };
type PersonNew = PartialWithNewMember<Person>;
/*
type PersonNew = {
name?: string | undefined;
age?: number | undefined;
newMember: boolean;
}
*/
const person2: PersonNew = {
name: 'νκΈΈλ',
newMember: true,
};
Enum νμ κ°λ νκΈ°
맡λ νμ μ μ΄μ©νλ©΄ Enum νμ μ νμ©λλ₯Ό λμΌ μ μλ€.
enum Fruit {
Apple,
Banana,
Orange,
}
const FRUIT_PRICE: { [key in Fruit]: number } = {
[Fruit.Apple]: 1000,
[Fruit.Banana]: 1500,
[Fruit.Orange]: 2000,
};
μλ₯Ό λ€μ΄μ μμ μ½λμ κ°μ΄ Fruit λΌλ enum νμ μ΄ μλλ°, FRUIT_PRICE λΌλ μμμμ λͺ¨λ κ³ΌμΌ κ°κ²©μ κ΄λ¦¬νλ€κ³ κ°μ μ ν΄λ³΄λ©΄, λ§μ½ enum νμ μ΄ λ³νκ° μμλ λ€μκ³Ό κ°μ΄ λΉ¨κ°μ€λ‘ κ²½κ³ λ₯Ό ν΄μ€λ€.


μ΄μ²λΌ μ½λ μμ μ΄ νμνλ©΄ 맡λ νμ μ μν΄μ λΉ¨κ°μ€μ΄ λμ μ€μλ₯Ό μ€μΌ μ μλ€.
μ νΈλ¦¬ν° νμ μκ°
맡λ νμ μ μ리λ₯Ό μ΄ν΄νλλ° μμ΄ μ΄ κΈμ λκΉμ§ 보μ μ¬λ¬λΆλ€κ» λ Έκ³ λ₯Ό μΉννλ€.

μ΄μ²λΌ 맡λ νμ λ¬Έλ²μ μ΄μ©ν΄ μΆ©λΆν νμ μ λ³νν μ μμ§λ§, μ νΈλ¦¬ν° νμ μ μ°λ©΄ μ΄λ―Έ μ μν΄ λμ νμ μ λ³ννκ±°λ μ½λλ₯Ό μ€μ¬ κ°κ²°νκ² μ μν μ μλ€.
μ¬μ€ μμμ λ€λ£¨μλ, Readonly λ Partial, Pick λ±μ μλ μ΄λ―Έ νμ μ€ν¬λ¦½νΈ κ°λ°μ§λ€μ΄ λ§λ€μ΄ λμ 맡λ νμ λ€μ΄λ€. μ΄λ¬ν 미리 λ§λ€μ΄μ§ 맡λ νμ μ μ νΈλ¦¬ν° νμ μ΄λΌκ³ λΆλ₯Έλ€κ³ μ΄ν΄νλ©΄ λλ€.
μ νΈλ¦¬ν° νμ μ λν΄μλ λ€μ ν¬μ€ν μ μ°Έκ³ νκΈΈ λ°λλ€.
[TS] π νμ μ€ν¬λ¦½νΈ - μ νΈλ¦¬ν° νμ π― μ΄μ 리 (+ μμ©)
νμ μ€ν¬λ¦½νΈ - Utility Types μ§κΈκΉμ§ νμ μ€ν¬λ¦½νΈλ₯Ό λ€λ£¨λ©΄μ, μλ°μ€ν¬λ¦½νΈλ₯Ό μ΄λμ λ μλκΉ νμ μ’ λ₯λ§ λ°°μ°λ©΄ λλ± λ§μ€ν° ν μ€ μμλλ, νμ μ체λ₯Ό μ½λ©νλ©° μλ¬μ€μ μ¬λΌμ§κ² ν
inpa.tistory.com
interface Product {
name: string;
phone: number;
address: string;
company: string;
}
type UpdateProduct = Partial<Product> // λͺ¨λ μμ±μ μ΅μ
λλ‘ λ§λ€μ΄μ£Όλ μ νΈλ¦¬ν° νμ
/*
type UpdateProduct = {
name?: string | undefined;
phone?: number | undefined;
address?: string | undefined;
company?: string | undefined;
}
*/
function updateProductItem(productItem: UpdateProduct) {
}
# μ°Έκ³ μλ£
https://typescript-kr.github.io/pages/advanced-types.html
μ΄μ¬μΉ νμ μ€ν¬λ¦½νΈ μμνκΈ°
μ λ‘μ΄ νμ μ€ν¬λ¦½νΈ μ¬μΈμ
μ½κ² μμνλ νμ μ€ν¬λ¦½νΈ (κΈΈλ², 2023, μΊ‘ν΄νκ΅ μ§μ)
μ΄ κΈμ΄ μ’μΌμ ¨λ€λ©΄ ꡬλ & μ’μμ
μ¬λ¬λΆμ ꡬλ
κ³Ό μ’μμλ
μ μμκ² ν° νμ΄ λ©λλ€.