Next.js
팁

🎯 10λΆ„ 투자둜 Typescript νƒ€μž…μŠ€ν¬λ¦½νŠΈ 정볡

μ€‘λ…„κ°œλ°œμž
μ€‘λ…„κ°œλ°œμž

@loxo

24일 μ „

28

🎯 10λΆ„ κ°•μ˜λ‘œ νƒ€μž…μŠ€ν¬λ¦½νŠΈ 정볡

μ‹œμž‘μ΄ λ°˜μ΄λ‹€ (50%)
거의 싀무적 μž…μž₯μ—μ„œ λ³΄μ•˜μ„ λ•Œ 이것 이상은 초고수의 μ˜μ—­μ΄λΌκ³  μƒκ°ν•©λ‹ˆλ‹€.
κ·ΈλŸ¬λ‚˜ 이 μ •λ„λŠ” κΈ°μ–΅ν•˜κ³  μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ°˜λ³΅ν•  μˆ˜λ°–μ— μ—†μŠ΅λ‹ˆλ‹€.
특히 κ°œλ°œμžλ“€μ΄ falsy 쑰건을 λͺ°λΌ if문을 κΈ°μ€€ 없이 λ‚¨λ°œν•˜κ³  μžˆμ–΄μš”. 정말 μ€‘μš”ν•©λ‹ˆλ‹€.
if (!variable), if(variable)둜 κ°„λ‹¨νžˆ ν•  수 μžˆλŠ” 것도 원리λ₯Ό λͺ°λΌμ„œ κ·Έλ ‡λ‹€κ³  생각이 λ©λ‹ˆλ‹€.


0️⃣ κ°•μ˜ ν•œ 쀄 μš”μ•½ (30초)

  • νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” μƒˆ μ–Έμ–΄κ°€ μ•„λ‹ˆλ‹€
  • μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œμ— νƒ€μž…μ„ 뢙인 것이 μ „λΆ€λ‹€
  • νƒ€μž…μ€ 싀행을 λ°”κΎΈμ§€ μ•Šκ³ ,
    πŸ‘‰ μ‹€μˆ˜μ™€ 버그λ₯Ό β€œμž‘μ„± 쀑”에 μž‘μ•„μ€€λ‹€

1️⃣ κ°€μž₯ λ¨Όμ € μ•Œμ•„μ•Ό ν•  것: if λ¬Έκ³Ό boolean (1λΆ„)

❌ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν˜„μ‹€

js
if (value) { // true일 μˆ˜λ„, false일 μˆ˜λ„, λ¬Έμžμ—΄μΌ μˆ˜λ„, 숫자일 μˆ˜λ„β€¦ }

❗ if λ¬Έμ—μ„œ false둜 ν‰κ°€λ˜λŠ” λͺ¨λ“  쑰건 (Falsy κ°’)

μžλ°”μŠ€ν¬λ¦½νŠΈ / νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ if (value)κ°€ falseκ°€ λ˜λŠ” 값은 μ•„λž˜λ‘œ κ³ μ •λ˜μ–΄ μžˆλ‹€.

ts
false 0 -0 0n // BigInt zero "" // 빈 λ¬Έμžμ—΄ null undefined NaN

πŸ‘‰ 이 κ°’λ“€λ§Œ false이고, λ‚˜λ¨Έμ§€λŠ” μ „λΆ€ true (Truthy)


❌ μ‹€λ¬΄μ—μ„œ κ°€μž₯ 많이 ν„°μ§€λŠ” 버그

ts
if (user.age) { // ageκ°€ 0이면 μ—¬κΈ° μ‹€ν–‰ μ•ˆ 됨 ❌ }
ts
if (user.name) { // name이 ""(빈 λ¬Έμžμ—΄)이면 false ❌ }

βœ… νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ 핡심 ν•΄κ²° 방식

ts
if (user.age !== null && user.age !== undefined) { // 0도 정상 κ°’μœΌλ‘œ 처리 βœ… }
ts
if (user.name !== undefined) { // 빈 λ¬Έμžμ—΄ ν—ˆμš© μ—¬λΆ€λ₯Ό λͺ…ν™•νžˆ νŒλ‹¨ }

boolean νƒ€μž…μ€ μ™„μ „νžˆ λ‹€λ₯΄λ‹€

ts
const isLoggedIn: boolean = false; if (isLoggedIn) { // 였직 true일 λ•Œλ§Œ μ‹€ν–‰ }

πŸ‘‰ boolean νƒ€μž…μ€ falsy κ°œλ…μ΄ μ•„λ‹ˆλΌ true / false만 쑴재


πŸ”₯ 싀무 핡심 포인트

  • if (value)λŠ” κ°’ 검사 + νƒ€μž… 검사λ₯Ό λ™μ‹œμ— ν•œλ‹€
  • 숫자, λ¬Έμžμ—΄μ€ κ·ΈλŒ€λ‘œ μ“°λ©΄ μœ„ν—˜ν•˜λ‹€
  • null / undefined μ²΄ν¬λŠ” 항상 λͺ…μ‹œμ μœΌλ‘œ
  • 쑰건문을 λ―Ώκ³  μ‹Άλ‹€λ©΄ πŸ‘‰ νƒ€μž…λΆ€ν„° μ’ν˜€λΌ

2️⃣ κΈ°λ³Έ νƒ€μž…: 이거면 80% 끝 (2λΆ„)

정말 자주 μ“°λŠ” κΈ°λ³Έ νƒ€μž…

λͺ¨λ‘ μ†Œλ¬Έμžμž…λ‹ˆλ‹€. κΌ­ κΈ°μ–΅ν•˜μ„Έμš”

ts
const userId: number = 1; const userName: string = "kim"; const isActive: boolean = true;

λ°°μ—΄

ts
const numbers: number[] = [1, 2, 3]; const names: string[] = ["kim", "lee"];

객체 (inline)

ts
const user: { id: number; name: string; } = { id: 1, name: "kim", };

null / undefined

ts
let value: string | null = null;

πŸ‘‰ μ‹€λ¬΄μ—μ„œλŠ” 거의 항상 | null을 μ‚¬μš©


3️⃣ ν•¨μˆ˜ νƒ€μž…: μ‹€λ¬΄μ—μ„œ 제일 μ€‘μš” (2λΆ„)

λ§€κ°œλ³€μˆ˜ + λ°˜ν™˜ νƒ€μž…

ts
function add(a: number, b: number): number { return a + b; }

ν™”μ‚΄ν‘œ ν•¨μˆ˜

ts
const multiply = (a: number, b: number): number => { return a * b; };

λ°˜ν™˜κ°’μ΄ 없을 λ•Œ

ts
function log(message: string): void { console.log(message); }

πŸ”₯ 싀무 포인트

  • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜λ§Œ 봐도 무슨 역할인지 λ°”λ‘œ μ•Œ 수 있음
  • API, μœ ν‹Έ ν•¨μˆ˜μ—μ„œ 버그 급감

4️⃣ interface vs type (κ°€μž₯ 많이 λ¬Όμ–΄λ³΄λŠ” 질문) (2λΆ„)

interface (객체 ꡬ쑰 μ •μ˜μš©)

ts
interface User { id: number; name: string; }

type (더 λ²”μš©μ )

ts
type User = { id: number; name: string; };

차이 핡심 μš”μ•½

ꡬ뢄interfacetype
객체 μ •μ˜βœ… μ΅œμ βœ… κ°€λŠ₯
ν™•μž₯extends&
μœ λ‹ˆμ˜¨ νƒ€μž…βŒβœ…
싀무 μ‚¬μš© λΉˆλ„λ§€μš° λ†’μŒλ§€μš° λ†’μŒ

ν™•μž₯ 비ꡐ

ts
interface Admin extends User { role: string; }
ts
type Admin = User & { role: string; };

βœ… 싀무 κΈ°μ€€ μΆ”μ²œ

  • 객체 ꡬ쑰 β†’ interface
  • μœ λ‹ˆμ˜¨ / μ‘°ν•© β†’ type

5️⃣ μœ λ‹ˆμ˜¨ νƒ€μž…: νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ μ§„μ§œ 힘 (1.5λΆ„)

ts
type Status = "loading" | "success" | "error"; let status: Status = "loading";

쑰건문이 μ™„μ „νžˆ 달라진닀

ts
if (status === "success") { // μ—¬κΈ°μ„  success ν™•μ • }

πŸ‘‰ λ¬Έμžμ—΄ 비ꡐ가 μ•„λ‹ˆλΌ β€œνƒ€μž… 비ꡐ”


6️⃣ 싀무 μ΅œλΉˆλ„ νŒ¨ν„΄: optional (?) + 쑰건문 (1λΆ„)

1️⃣ optional property (?) β€” 값이 없을 μˆ˜λ„ μžˆλ‹€λŠ” μ„ μ–Έ

ts
interface User { id: number; name?: string; // μžˆμ–΄λ„ 되고, 없어도 λœλ‹€ }

πŸ‘‰ name?: string의 μ§„μ§œ μ˜λ―ΈλŠ” μ•„λž˜μ™€ κ°™λ‹€

ts
name: string | undefined

2️⃣ optional + if λ¬Έ (νƒ€μž… 쒁히기)

ts
if (user.name) { // μ—¬κΈ°μ„œλŠ” name이 string으둜 ν™•μ • }

⚠️ 단, 빈 λ¬Έμžμ—΄ ""은 falseκ°€ λœλ‹€

ts
if (user.name !== undefined) { // 빈 λ¬Έμžμ—΄λ„ 정상 κ°’μœΌλ‘œ 인정 }

3️⃣ optional chaining (?.) β€” μ‹€λ¬΄μ—μ„œ μ§„μ§œ 많이 씀

ts
user.profile?.imageUrl

πŸ”₯ 싀무 핡심 포인트

  • ?λŠ” 값이 없을 수 μžˆμŒμ„ λ¬Έμ„œλ‘œ κ³ μ •ν•˜λŠ” 도ꡬ
  • optional은 λŒ€λΆ€λΆ„ λ°±μ—”λ“œ 응닡 / μ™ΈλΆ€ λ°μ΄ν„°μ—μ„œ μ‚¬μš©
  • optional을 μ“°λŠ” μˆœκ°„ πŸ‘‰ if 쑰건을 더 μ‹ μ€‘νžˆ 써야 ν•œλ‹€

6️⃣-1️⃣ if falsy 싀무 νŒ¨ν„΄ μš”μ•½ (자주 μ“°λŠ” κ²ƒλ§Œ)

βœ”οΈ νŒ¨ν„΄ 1: κ°’ 쑴재 μ—¬λΆ€λ§Œ 확인 (early return)

ts
if (!value) return;
  • null, undefined, "", 0 λͺ¨λ‘ κ±°λ₯Έλ‹€
  • UI 이벀트, κ°€λ“œ λ‘œμ§μ—μ„œ κ°€μž₯ 흔함

βœ”οΈ νŒ¨ν„΄ 2: null / undefined 만 체크 (싀무 μ΅œμ€‘μš”)

ts
if (value == null) return;
  • null λ˜λŠ” undefined 만
  • 0, "", false λŠ” 톡과

βœ”οΈ νŒ¨ν„΄ 3: optional κ°’ μ ‘κ·Ό

ts
if (user.profile?.imageUrl) { // imageUrl μžˆμ„ λ•Œλ§Œ }

7️⃣ 싀무 ν•„μˆ˜ λ‚΄μž₯ νƒ€μž… (Utility Types) (2λΆ„)

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—λŠ” μ‹€λ¬΄μ—μ„œ 맀일 μ“°λŠ” λ‚΄μž₯ νƒ€μž…μ΄ 이미 μ€€λΉ„λ˜μ–΄ μžˆλ‹€.


1️⃣ Partial β€” μ „λΆ€ optional둜 λ§Œλ“€κΈ°

ts
interface User { id: number; name: string; email: string; } type UserUpdate = Partial<User>;

πŸ‘‰ PATCH API, μˆ˜μ • ν™”λ©΄μ—μ„œ ν•„μˆ˜


2️⃣ Omit<T, K> β€” νŠΉμ • ν•„λ“œ 제거

ts
type UserWithoutId = Omit<User, "id">;

3️⃣ Pick<T, K> β€” ν•„μš”ν•œ κ²ƒλ§Œ 선택

ts
type UserPreview = Pick<User, "id" | "name">;

4️⃣ Required β€” optional 제거

ts
type RequiredUser = Required<User>;

5️⃣ Record<K, T> β€” key/value 객체λ₯Ό κ°€μž₯ μ•ˆμ „ν•˜κ²Œ

ts
type Role = "admin" | "user" | "guest"; type RoleLabelMap = Record<Role, string>; const ROLE_LABEL: RoleLabelMap = { admin: "κ΄€λ¦¬μž", user: "일반 μ‚¬μš©μž", guest: "μ†λ‹˜", };

의미:

  • key 집합을 νƒ€μž…μœΌλ‘œ κ³ μ •
  • λΉ μ§„ key, 잘λͺ»λœ keyλ₯Ό 컴파일 λ‹¨κ³„μ—μ„œ 차단

❌ 객체λ₯Ό κ·Έλƒ₯ μ“°λ©΄ μƒκΈ°λŠ” 문제

ts
const ROLE_LABEL = { admin: "κ΄€λ¦¬μž", user: "일반 μ‚¬μš©μž", }; // guest 빠져도 μ—λŸ¬ μ—†μŒ ❌

βœ… Recordλ₯Ό μ“°λ©΄

ts
const ROLE_LABEL: Record<Role, string> = { admin: "κ΄€λ¦¬μž", user: "일반 μ‚¬μš©μž", guest: "μ†λ‹˜", };

πŸ‘‰ λͺ¨λ“  key κ°•μ œ β†’ μ„€μ • 객체, μƒμˆ˜ 맡에 졜적


πŸ”₯ Utility Type 핡심 정리

  • νƒ€μž…μ„ μƒˆλ‘œ λ§Œλ“€μ§€ 말고 μ‘°ν•©ν•˜λΌ
  • Partial / Pick / Omit / Required / Record
  • 이 5개면 싀무 νƒ€μž…μ˜ 90% ν•΄κ²°

8️⃣ typeof β€” κ°’μ—μ„œ νƒ€μž…μ„ λ½‘μ•„λ‚΄λŠ” 싀무 핡심 (1λΆ„)

typeofλŠ” λŸ°νƒ€μž„ κ°’μœΌλ‘œλΆ€ν„° νƒ€μž…μ„ μž¬μ‚¬μš©ν•˜κ²Œ ν•΄μ€€λ‹€.


1️⃣ μƒμˆ˜ 객체 β†’ νƒ€μž…μœΌλ‘œ λ§Œλ“€κΈ° (μ΅œλΉˆλ„)

ts
const ROLE_LABEL = { admin: "κ΄€λ¦¬μž", user: "일반 μ‚¬μš©μž", guest: "μ†λ‹˜", } as const; type RoleLabelMap = typeof ROLE_LABEL;

의미:

  • κ°’κ³Ό νƒ€μž…μ„ ν•œ 번만 μ •μ˜
  • νƒ€μž…κ³Ό 값이 μ ˆλŒ€ μ–΄κΈ‹λ‚˜μ§€ μ•ŠμŒ

2️⃣ typeof + keyof β€” key νƒ€μž… 뽑기 (싀무 μ‘°ν•©)

ts
type Role = keyof typeof ROLE_LABEL; // "admin" | "user" | "guest"

πŸ‘‰ enum λŒ€μ²΄ νŒ¨ν„΄ (κ°€μž₯ 많이 씀)


3️⃣ ν•¨μˆ˜ λ°˜ν™˜ νƒ€μž… μž¬μ‚¬μš©

ts
function createUser() { return { id: 1, name: "kim", }; } type User = ReturnType<typeof createUser>;

πŸ‘‰ API 응닡, νŒ©ν† λ¦¬ ν•¨μˆ˜μ—μ„œ 맀우 유용


❌ typeofλ₯Ό μ•ˆ μ“°λ©΄ μƒκΈ°λŠ” 문제

ts
const CONFIG = { retry: 3, timeout: 1000, }; // νƒ€μž…μ„ λ”°λ‘œ 또 μž‘μ„± interface Config { retry: number; timeout: number; }

πŸ‘‰ κ°’κ³Ό νƒ€μž…μ΄ μ‰½κ²Œ 어긋남


πŸ”₯ typeof 싀무 핡심 μš”μ•½

  • 값이 이미 있으면 νƒ€μž…μ„ λ‹€μ‹œ λ§Œλ“€μ§€ 말 것
  • typeofλŠ” νƒ€μž… 쀑볡을 μ œκ±°ν•˜λŠ” 도ꡬ
  • Record / keyof 와 ν•¨κ»˜ μ“°λ©΄ μœ„λ ₯이 폭발
#TypeScript#νƒ€μž…μŠ€ν¬λ¦½νŠΈ#JavaScript#Falsy#νƒ€μž… 체크

λŒ“κΈ€ 0

Ctrl + Enterλ₯Ό 눌러 등둝할 수 μžˆμŠ΅λ‹ˆλ‹€
β€» AI λ‹€λ“¬κΈ°λŠ” λ‚΄μš©μ„ μ •μ œν•˜λŠ” 보쑰 κΈ°λŠ₯이며, μ΅œμ’… λ‚΄μš©μ€ μ‚¬μš©μžκ°€ 확인해야 ν•©λ‹ˆλ‹€.