JiSoo's Devlog

[μš°μ•„ν•œ νƒ€μž…μŠ€ν¬λ¦½νŠΈ] 5μž₯ λ³Έλ¬Έ

Frontend/Typescript

[μš°μ•„ν•œ νƒ€μž…μŠ€ν¬λ¦½νŠΈ] 5μž₯

μ§€μˆ­μˆ­μˆ­ 2025. 5. 28. 13:05

πŸ“ 쑰건뢀 νƒ€μž…

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ 쑰건뢀 νƒ€μž…μ€ Condition ? A : B ν˜•νƒœλ₯Ό κ°€μ§„λ‹€.

쑰건뢀 νƒ€μž…μ„ ν™œμš©ν•˜λ©΄ μ€‘λ³΅λ˜λŠ” νƒ€μž… μ½”λ“œλ₯Ό μ œκ±°ν•˜κ³  상황에 따라 μ μ ˆν•œ νƒ€μž…μ„ 얻을 수 있기 λ•Œλ¬Έμ— μ •ν™•ν•œ νƒ€μž… 좔둠이 κ°€λŠ₯ν•˜λ‹€.

 

extends와 μ œλ„€λ¦­μ„ ν™œμš©ν•œ 쑰건뢀 νƒ€μž…

extends ν‚€μ›Œλ“œλŠ” νƒ€μž…μ„ ν™•μž₯ν•  λ•Œμ™€ νƒ€μž…μ„ μ‘°κ±΄λΆ€λ‘œ μ„€μ •ν•  λ•Œ μ‚¬μš©λ˜λ©° μ œλ„€λ¦­ νƒ€μž…μ—μ„œλŠ” ν•œμ •μž μ—­ν• λ‘œλ„ μ‚¬μš©λœλ‹€.

T extends U ? X : Y

쑰건뢀 νƒ€μž…μ—μ„œ extendsλ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ μ‚Όν•­ μ—°μ‚°μžμ™€ ν•¨κ»˜ μ“΄λ‹€.

μœ„ ν‘œν˜„μ€ νƒ€μž… Tλ₯Ό U에 ν• λ‹Ήν•  수 있으면 X νƒ€μž…, μ•„λ‹ˆλ©΄ Y νƒ€μž…μœΌλ‘œ 결정됨을 μ˜λ―Έν•œλ‹€.

 

inferλ₯Ό ν™œμš©ν•΄μ„œ νƒ€μž… μΆ”λ‘ ν•˜κΈ°

extendsλ₯Ό μ‚¬μš©ν•  λ•Œ infer ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

inferλŠ” νƒ€μž…μ„ μΆ”λ‘ ν•˜λŠ” 역할을 ν•œλ‹€.

μ‚Όν•­ μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•œ 쑰건문의 ν˜•νƒœλ₯Ό κ°€μ§€λŠ”λ° extends둜 쑰건을 μ„œμˆ ν•˜κ³  infer둜 νƒ€μž…μ„ μΆ”λ‘ ν•˜λŠ” 방식을 μ·¨ν•œλ‹€.

type UnpackPromise<T> = T extends Promise<infer K>[] ? K :any;

UnpackPromise νƒ€μž…μ€ μ œλ„€λ¦­μœΌλ‘œ Tλ₯Ό λ°›μ•„ Tκ°€ Promise둜 λž˜ν•‘λœ 경우라면 Kλ₯Ό λ°˜ν™˜ν•˜κ³  κ·Έλ ‡μ§€ μ•Šμ€ κ²½μš°μ—λŠ” anyλ₯Ό λ°˜ν™˜ν•œλ‹€.

Promise<infer K>λŠ” Promise의 λ°˜ν™˜ 값을 μΆ”λ‘ ν•΄ ν•΄λ‹Ή κ°’μ˜ νƒ€μž…μ„ K둜 ν•œλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

 

 

 πŸŒŸ ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž… ν™œμš©ν•˜κΈ°

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” μœ λ‹ˆμ˜¨ νƒ€μž…μ„ μ‚¬μš©ν•΄ λ³€μˆ˜ νƒ€μž…μ„ νŠΉμ • λ¬Έμžμ—΄λ‘œ μ§€μ •ν•  수 μžˆλ‹€.

type HeaderTag = "h1" | "h2" | "h3" | "h4" | "h5";

이 κΈ°λŠ₯을 μ‚¬μš©ν•˜λ©΄ μ»΄νŒŒμΌνƒ€μž„μ˜ λ³€μˆ˜μ— ν• λ‹Ήλ˜λŠ” νƒ€μž…μ„ νŠΉμ • λ¬Έμžμ—΄λ‘œ μ •ν™•νžˆ 검사해 휴먼 μ—λŸ¬λ₯Ό λ°©μ§€ν•  수 있고 μžλ™ μ™„μ„± κΈ°λŠ₯을 톡해 개발 생산성을 높일 수 μžˆλ‹€.

ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…μ€ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ 문법을 μ‚¬μš©ν•΄ νŠΉμ • λ¬Έμžμ—΄μ— λŒ€ν•œ νƒ€μž…μ„ μ„ μ–Έν•  수 μžˆλŠ” κΈ°λŠ₯이닀.

type Heading Number =  1 | 2 | 3 | 4 | 5;
type HeaderTag = `h${HeadingNumber}`;
type Vertical = "top" | "bottom";
type Horizon = "left" | "right";

type Direction = Vertical } `${Vertical}${Capitalize<Horizon>}`;

ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…μ„ μ‚¬μš©ν•˜λ©΄ λ”μš± 읽기 μ‰¬μš΄ μ½”λ“œλ‘œ μž‘μ„± κ°€λŠ₯ν•˜κ³  μ½”λ“œλ₯Ό μž¬μ‚¬μš©ν•˜κ³  μˆ˜μ •ν•˜λŠ” 데 μš©μ΄ν•œ νƒ€μž…μ„ μ„ μ–Έν•  수 μžˆλ‹€.

μ£Όμ˜ν•  점
μ»΄νŒŒμΌλŸ¬κ°€ μœ λ‹ˆμ˜¨μ„ μΆ”λ‘ ν•˜λŠ” 데 μ‹œκ°„μ΄ 였래 걸리면 λΉ„νš¨μœ¨μ μ΄λΌ νƒ€μž…μ„ μΆ”λ‘ ν•˜μ§€ μ•Šκ³  μ—λŸ¬λ₯Ό 내뱉을 λ•Œκ°€ μžˆλ‹€.
λ”°λΌμ„œ ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…μ— μ‚½μž…λœ μœ λ‹ˆμ˜¨ μ‘°ν•©μ˜ 경우의 μˆ˜κ°€ λ„ˆλ¬΄ λ§Žμ§€ μ•Šκ²Œ 적절히 λ‚˜λˆ  νƒ€μž…μ„ μ •μ˜ν•˜λŠ” 게 μ’‹λ‹€.

 

 

🎢 μ»€μŠ€ν…€ μœ ν‹Έλ¦¬ν‹° νƒ€μž… ν™œμš©ν•˜κΈ°

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ μ œκ³΅ν•˜λŠ” μœ ν‹Έλ¦¬ν‹° νƒ€μž…λ§ŒμœΌλ‘œ ν‘œν˜„ν•˜λŠ” 데 ν•œκ³„κ°€ μžˆμ„ λ•Œ μ»€μŠ€ν…€ μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ„ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

 

μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ₯Ό ν™œμš©ν•΄ styled-components의 쀑볡 νƒ€μž… μ„ μ–Έ ν”Όν•˜κΈ°

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈ κ΅¬ν˜„ μ‹œ μ—¬λŸ¬ μ˜΅μ…˜μ„ props둜 λ°›μ•„ μœ μ—°ν•œ μ»΄ν¬λ„ŒνŠΈλ‘œ λ§Œλ“€ 수 μžˆλ‹€.

μŠ€νƒ€μΌ κ΄€λ ¨ propsλŠ” styled-components에 μ „λ‹¬λ˜λ©° styled-components에도 ν•΄λ‹Ή νƒ€μž…μ„ μ •ν™•νžˆ μž‘μ„±ν•΄μ•Ό ν•œλ‹€.

이런 경우 Pick, Omit 같은 μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ„ 잘 ν™œμš©ν•΄ μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ²Œ μž‘μ„±ν•  수 μžˆλ‹€.

Pick μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ„ ν™œμš©ν•΄ νƒ€μž…μ„ μ •μ˜ν•˜λ©΄ μ€‘λ³΅λœ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•Šμ•„λ„ 되고 μœ μ§€λ³΄μˆ˜λ₯Ό λ”μš± νŽΈλ¦¬ν•˜κ²Œ ν•  수 μžˆλ‹€.

 

PickOne μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—λŠ” μ„œλ‘œ λ‹€λ₯Έ 2개 μ΄μƒμ˜ 객체λ₯Ό μœ λ‹ˆμ˜¨ νƒ€μž…μœΌλ‘œ 받을 λ•Œ νƒ€μž… 검사가 μ œλŒ€λ‘œ μ§„ν–‰λ˜μ§€ μ•ŠλŠ” μ΄μŠˆκ°€ μžˆλ‹€.

이런 문제 해결을 μœ„ν•΄ PickOne μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

type Card = {
  card: string
};

type Account = {
  account: string
};

function withdraw(type: Card | Account) {
  ...
}

withdraw({ card: "tyundai", account: "hana" });

μœ„ μ½”λ“œμ²˜λŸΌ Cardλ‚˜ Account 쀑 ν•˜λ‚˜λ§Œ λ°›κ³  싢은 μƒν™©μ—μ„œ μ €λ ‡κ²Œ νƒ€μž…μ„ μž‘μ„±ν•˜λ©΄ μ˜λ„λŒ€λ‘œ νƒ€μž… 검사가 이뀄지지 μ•ŠλŠ”λ‹€.

withdraw ν•¨μˆ˜μ˜ 인자둜 λ‘˜ 쀑 ν•˜λ‚˜λ§Œ λ°›κ³  μ‹Άμ§€λ§Œ μ‹€μ œλ‘œλŠ” card, account 속성 λ‘˜ λ‹€ 받아도 νƒ€μž… μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

이 μ΄μœ λŠ” μ§‘ν•© κ΄€μ μœΌλ‘œ λ³Ό λ•Œ μœ λ‹ˆμ˜¨μ€ 합집합이 되기 λ•Œλ¬Έμ΄λ‹€.

이런 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 식별할 수 μžˆλŠ” μœ λ‹ˆμ˜¨ 기법을 자주 ν™œμš©ν•œλ‹€.

 

식별할 수 μžˆλŠ” μœ λ‹ˆμ˜¨μœΌλ‘œ 객체 νƒ€μž…μ„ μœ λ‹ˆμ˜¨μœΌλ‘œ λ°›κΈ°

식별할 수 μžˆλŠ” μœ λ‹ˆμ˜¨μ€ 각 νƒ€μž…μ— typeμ΄λΌλŠ” 곡톡 속성을 μΆ”κ°€ν•΄ κ΅¬λΆ„μ§“λŠ” 방법이닀.

type Card = {
  type: "card";
  card: string;
};
type Account = {
  type: "account";
  account: string;
};

function withdraw(type: Card | Account) {
  ...
}

withdraw({ type: "card", card: "hyundai" });
withdraw({ type: "account", account: "hana" });

μœ„μ²˜λŸΌ 식별할 수 μžˆλŠ” μœ λ‹ˆμ˜¨μ„ ν™œμš©ν•˜λ©΄ κ³΅ν†΅λœ 속성인 type을 κΈ°μ€€μœΌλ‘œ 객체λ₯Ό ꡬ뢄할 수 μžˆμ–΄ withdraw ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ³³μ—μ„œ μ •ν™•ν•œ νƒ€μž…μ„ μΆ”λ‘ ν•  수 있게 λœλ‹€.

 

NonNullable νƒ€μž… 검사 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ κ°„νŽΈν•˜κ²Œ νƒ€μž… κ°€λ“œν•˜κΈ°

null을 κ°€μ§ˆ 수 μžˆλŠ” κ°’μ˜ null μ²˜λ¦¬λŠ” 자주 μ‚¬μš©λ˜λŠ” νƒ€μž… κ°€λ“œ νŒ¨ν„΄μ˜ ν•˜λ‚˜μ΄λ‹€.

일반적으둜 if문을 μ‚¬μš©ν•΄ null 처리 νƒ€μž… κ°€λ“œλ₯Ό μ μš©ν•˜μ§€λ§Œ is ν‚€μ›Œλ“œμ™€ NonNullable νƒ€μž…μœΌλ‘œ νƒ€μž… 검사λ₯Ό μœ„ν•œ μœ ν‹Έ ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€.

 

NonNullable νƒ€μž…μ΄λž€

μ œλ„€λ¦­μœΌλ‘œ λ°›λŠ” Tκ°€ nullμ΄λ‚˜ undefined일 λ•Œ never λ˜λŠ” Tλ₯Ό λ°˜ν™˜ν•˜λŠ” νƒ€μž…μ΄λ‹€.

NonNullable을 μ‚¬μš©ν•˜λ©΄ nullμ΄λ‚˜ undefinedκ°€ μ•„λ‹ˆ 경우λ₯Ό μ œμ™Έν•  수 μžˆλ‹€.

type NonNullable<T> = T extends null | undefined ? never : T;

 

null, undefinedλ₯Ό κ²€μ‚¬ν•΄μ£ΌλŠ” NonNullable ν•¨μˆ˜

NonNullable μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ„ μ‚¬μš©ν•΄ nullμ΄λ‚˜ undefinedλ₯Ό 검사해 μ£ΌλŠ” νƒ€μž… κ°€λ“œ ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ μ“Έ 수 μžˆλ‹€.

NonNullable ν•¨μˆ˜λŠ” λ§€κ°œλ³€μˆ˜μΈ valueκ°€ nullμ΄λ‚˜ undefined라면 falseλ₯Ό λ°˜ν™˜ν•œλ‹€.

 

 

πŸ‘½ λΆˆλ³€ 객체 νƒ€μž…μœΌλ‘œ ν™œμš©ν•˜κΈ°

μƒμˆ«κ°’μ„ 관리할 λ•Œ 객체λ₯Ό μ‚¬μš©ν•˜λŠ”λ° theme 객체, μ• λ‹ˆλ©”μ΄μ…˜ 객체 λ“± λ‹€μ–‘ν•˜κ²Œ ν™œμš©λœλ‹€.

이런 객체λ₯Ό μ‚¬μš©ν•  λ•Œ μ—΄λ¦° νƒ€μž…μœΌλ‘œ μ„€μ •ν•  수 μžˆλ‹€.

keof, as const둜 객체 νƒ€μž…μ„ ꡬ체적을 μ„€μ •ν•˜λ©΄ νƒ€μž…μ— λ§žμ§€ μ•ŠλŠ” 값을 전달할 경우 νƒ€μž… μ—λŸ¬κ°€ λ°˜ν™˜λ˜κΈ° λ•Œλ¬Έμ— 컴파일 λ‹¨κ³„μ—μ„œ λ°œμƒν•  수 μžˆλŠ” μ‹€μˆ˜λ₯Ό λ°©μ§€ν•  수 있고 μžλ™ μ™„μ„± κΈ°λŠ₯을 톡해 객체에 μ–΄λ–€ 값이 μžˆλŠ”μ§€ μ‰½κ²Œ νŒŒμ•…ν•  수 μžˆλ‹€.

 

Atom μ»΄ν¬λ„ŒνŠΈμ—μ„œ theme style 객체 ν™œμš©ν•˜κΈ°

Atom λ‹¨μœ„μ˜ μž‘μ€ μ»΄ν¬λ„ŒνŠΈλŠ” 폰트 크기, 색상 λ“± λ‹€μ–‘ν•œ ν™˜κ²½μ—μ„œ μœ μ—°ν•˜κ²Œ μ‚¬μš©λ  수 있게 κ΅¬ν˜„λ˜μ–΄μ•Ό ν•˜λŠ”λ° 이런 섀정값을 props둜 λ„˜κ²¨μ£Όκ²Œ μ„€κ³„ν•œλ‹€.

props둜 직접 색상 값을 λ„˜κ²¨μ€„ μˆ˜λ„ μžˆμ§€λ§Œ 그러면 μ‚¬μš©μžκ°€ λͺ¨λ“  색상 값을 인지해야 ν•˜κ³  변경에 μ·¨μ•½ν•œ μƒνƒœκ°€ λœλ‹€.

이런 문제 해결을 μœ„ν•΄ μ—¬λŸ¬ ν”„λ‘œμ νŠΈμ—μ„œλŠ” μŠ€νƒ€μΌ 값을 κ΄€λ¦¬ν•˜λŠ” theme 객체λ₯Ό 두고 κ΄€λ¦¬ν•œλ‹€.

Atom μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” theme 객체의 색상, 폰트 μ‚¬μ΄μ¦ˆμ˜ 킀값을 props둜 받을 λ’€ theme κ°μ²΄μ—μ„œ 값을 λ°›μ•„μ˜€λ„λ‘ μ„€κ³„ν•œλ‹€.

 

keyof μ—°μ‚°μžλ‘œ 객체의 킀값을 νƒ€μž…μœΌλ‘œ μΆ”μΆœν•˜κΈ°

keyof μ—°μ‚°μžλŠ” 객체 νƒ€μž…μ„ λ°›μ•„ ν•΄λ‹Ή 객체의 킀값을 string λ˜λŠ” number의 λ¦¬ν„°λŸ΄ μœ λ‹ˆμ˜¨ νƒ€μž…μ„ λ°˜ν™˜ν•œλ‹€.

객체 νƒ€μž…μœΌλ‘œ 인덱슀 μ‹œκ·Έλ‹ˆμ²˜κ°€ μ‚¬μš©λ˜μ—ˆλ‹€λ©΄ keyofλŠ” 인덱슀 μ‹œκ·Έλ‹ˆμ²˜μ˜ ν‚€ νƒ€μž…μ„ λ°˜ν™˜ν•œλ‹€.

interface ColorType {
  red: string;
  green: string;
  blue: string;
}

type ColorKeyType = keyof ColorType; //'red' | 'green' | 'blue'

 

typeof μ—°μ‚°μžλ‘œ 값을 νƒ€μž…μœΌλ‘œ 닀루기

keyof μ—°μ‚°μžλŠ” 객체 νƒ€μž…μ„ λ°›κΈ° λ•Œλ¬Έμ— 객체의 킀값을 νƒ€μž…μœΌλ‘œ 닀루렀면 κ°’ 객체λ₯Ό νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•΄μ•Ό ν•œλ‹€.

μ΄λ•Œ typeof μ—°μ‚°μžλ₯Ό ν™œμš©ν•  수 μžˆλŠ”λ° λ³€μˆ˜λ‚˜ μ†μ„±μ˜ νƒ€μž…μ„ μΆ”λ‘ ν•˜λŠ” 역할을 ν•œλ‹€.

typeof μ—°μ‚°μžλŠ” λ‹¨λ…μœΌλ‘œ μ‚¬μš©λ˜κΈ°λ³΄λ‹€ 주둜 ReturnType같이 μœ ν‹Έλ¦¬ν‹° νƒ€μž…μ΄λ‚˜ keyof μ—°μ‚°μžμ²˜λŸΌ νƒ€μž…μ„ λ°›λŠ” μ—°μ‚°μžμ™€ ν•¨κ»˜ 쓰인닀.

const colors = {
  red: "#F45452",
  green: "#0C952A",
  blue: "#1A7CFF",
};

type ColorsType = typeof colors;
/**
{
  red: string;
  green: string;
  blue: string;
}
*/

 

 

 

728x90