LHS_EffectiveTypescript_05 - YDP-SPLOUNGE-CLUB/typescript-study GitHub Wiki

μ•„μ΄ν…œ 21 νƒ€μž… λ„“νžˆκΈ°

νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ λ„“νžˆκΈ°λ₯Ό 톡해 μƒμˆ˜μ˜ νƒ€μž…μ„ μΆ”λ‘ ν•˜λŠ” 법을 이해해야 ν•œλ‹€.

μ§€μ •λœ 단일 값을 κ°€μ§€κ³  ν• λ‹Ή κ°€λŠ₯ν•œ κ°’λ“€μ˜ 집합을 μœ μΆ”ν•΄μ•Ό ν•˜λŠ” 과정을 λ„“νžˆκΈ°(widening) 이라 ν•œλ‹€.

const μ‚¬μš©ν•˜κΈ°

let λŒ€μ‹  constλ₯Ό μ‚¬μš©ν•˜μ—¬ 더 쒁은 νƒ€μž…μ΄ λ˜λ„λ‘ ν•˜μž.

const x = 'x' // type is "x"  
let vec = { x: 10, y: 20, z: 30 }  
getComponent(vec, x) // OK

κ·ΈλŸ¬λ‚˜ 객체와 λ°°μ—΄μ˜ κ²½μš°μ—λŠ” μ—¬μ „νžˆ λ¬Έμ œκ°€ λ‚¨μ•„μžˆλ‹€. λ”°λΌμ„œ 객체의 경우 ν•œλ²ˆμ— λ§Œλ“€μ–΄μ•Ό ν•œλ‹€. (μ•„μ΄ν…œ23)

μ±…μ—μ„œλŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈ κΈ°λ³Έ λ™μž‘μ„ μž¬μ •μ˜ν•˜λŠ” μ„Έκ°€μ§€ 방법을 μ†Œκ°œν•œλ‹€.

  • λͺ…μ‹œμ  νƒ€μž… ꡬ문을 μ œκ³΅ν•˜λŠ” 방법
  • νƒ€μž… 체컀에 좔가적인 λ¬Έλ§₯을 μ œκ³΅ν•˜λŠ” 방법
  • const 단언문을 μ‚¬μš©ν•˜λŠ” 방법

λ™μž‘μ— 영ν–₯을 쀄 수 μžˆλŠ” 방법인 const, νƒ€μž… ꡬ문, λ¬Έλ§₯, as const에 μ΅μˆ™ν•΄μ Έμ•Ό ν•œλ‹€.

const 단언문과 λ³€μˆ˜ 선언에 μ“°μ΄λŠ” let, const 와 ν˜Όλ™ν•˜λ©΄ μ•ˆλœλ‹€. const 단언문은 μ˜¨μ „νžˆ νƒ€μž… κ³΅κ°„μ˜ 기법이닀.

const v1 = {  
  x: 1,  
  y: 2,  
} // Type is { x: number; y: number; }  
  
const v2 = {  
  x: 1 as const,  
  y: 2,  
} // Type is { x: 1; y: number; }  
  
const v3 = {  
  x: 1,  
  y: 2,  
} as const // Type is { readonly x: 1; readonly y: 2; }

const 단언문을 톡해 μ΅œλŒ€ν•œ 쒁은 νƒ€μž…μœΌλ‘œ μΆ”λ‘ ν•œλ‹€.

λ˜ν•œ 배열을 νŠœν”Œ νƒ€μž…μœΌλ‘œ μΆ”λ‘ ν•  λ•Œμ—λ„ as constλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

const a1 = [1, 2, 3] // Type is number[]  
const a2 = [1, 2, 3] as const // Type is readonly [1, 2, 3]

μ•„μ΄ν…œ 22 νƒ€μž… 쒁히기

λΆ„κΈ°λ¬Έ 외에도 μ—¬λŸ¬ μ’…λ₯˜μ˜ μ œμ–΄ 흐름을 μ‚΄νŽ΄λ³΄λ©° νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ νƒ€μž…μ„ μ’νžˆλŠ” 과정을 이해해야 ν•œλ‹€.

λΆ„κΈ°μ—μ„œ μ˜ˆμ™Έλ₯Ό λ˜μ§€κ±°λ‚˜ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜μ—¬ λΈ”λ‘μ˜ λ‚˜λ¨Έμ§€ λΆ€λΆ„μ—μ„œ λ³€μˆ˜μ˜ νƒ€μž…μ„ 쒁힐 수 μžˆλ‹€.

const el = document.getElementById('foo') // Type is HTMLElement | null  
if (!el) throw new Error('Unable to find #foo')  
el // Now type is HTMLElement  
el.innerHTML = 'Party Time'.blink()

instanceof λ₯Ό μ‚¬μš©ν•΄μ„œ νƒ€μž…μ„ 쒁힐 수 μžˆλ‹€.

function contains(text: string, search: string | RegExp) {  
  if (search instanceof RegExp) {  
    search // Type is RegExp  
    return !!search.exec(text)  
  }  search // Type is string  
  return text.includes(search)  
}

μ†μ„±μ²΄ν¬λ‘œλ„ νƒ€μž…μ„ 쒁힐 수 μžˆλ‹€.

interface A {  
  a: number  
}  
interface B {  
  b: number  
}  
function pickAB(ab: A | B) {  
  if ('a' in ab) {  
    ab // Type is A  
  } else {  
    ab // Type is B  
  }  
  ab // Type is A | B  
}

λ‚΄μž₯ν•¨μˆ˜λ₯Ό 톡해 νƒ€μž…μ„ 쒁힐 수 μžˆλ‹€.

function contains(text: string, terms: string | string[]) {  
  const termList = Array.isArray(terms) ? terms : [terms]  
  termList // Type is string[]  
  // ...}
}

νƒœκ·Έλœ/κ΅¬λ³„λœ μœ λ‹ˆμ˜¨κ³Ό μ‚¬μš©μž μ •μ˜ νƒ€μž… κ°€λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ νƒ€μž… μ’νžˆκΈ°μ™€ 과정을 μ›ν™œν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.

또 λ‹€λ₯Έ 방법은 'νƒœκ·Έ'λ₯Ό λΆ™μ΄λŠ” 방법이 μžˆλ‹€.

interface UploadEvent {  
  type: 'upload'  
  filename: string  
  contents: string  
}  
interface DownloadEvent {  
  type: 'download'  
  filename: string  
}  
type AppEvent = UploadEvent | DownloadEvent  
  
function handleEvent(e: AppEvent) {  
  switch (e.type) {  
    case 'download':  
      e // Type is DownloadEvent  
      break  
    case 'upload':  
      e // Type is UploadEvent  
      break  
  }  
}

이 νŒ¨ν„΄μ€ νƒœκ·Έλœ μœ λ‹ˆμ˜¨ λ˜λŠ” κ΅¬λ³„λœ μœ λ‹ˆμ˜¨ 이라고 λΆˆλ¦°λ‹€. λ§Œμ•½ νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ νƒ€μž…μ„ μ‹λ³„ν•˜μ§€ λͺ»ν•œλ‹€λ©΄, 식별을 돕기 μœ„ν•΄ μ»€μŠ€ν…€ ν•¨μˆ˜λ₯Ό λ„μž…ν•  수 μžˆλ‹€.

function isInputElement(el: HTMLElement): el is HTMLInputElement {  
  return 'value' in el  
}  
  
function getElementContent(el: HTMLElement) {  
  if (isInputElement(el)) {  
    el // Type is HTMLInputElement  
    return el.value  
  }  
  el // Type is HTMLElement  
  return el.textContent  
}

이 기법은 μ‚¬μš©μžμ •μ˜νƒ€μž…κ°€λ“œλ‘œ 뢈리며, λ°˜ν™˜ νƒ€μž…μ΄ true 일 경우 νƒ€μž… μ²΄μ»€μ—κ²Œ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ„ 쒁힐 수 μžˆλ‹€κ³  μ•Œλ €μ£ΌλŠ” 역할을 ν•œλ‹€.

μ•„μ΄ν…œ 23 ν•œκΊΌλ²ˆμ— 객체 μƒμ„±ν•˜κΈ°

속성을 제각각 μΆ”κ°€ν•˜μ§€ 말고 ν•œκΊΌλ²ˆμ— 객체둜 λ§Œλ“€μ–΄μ•Όν•©λ‹ˆλ‹€. μ•ˆμ „ν•œ νƒ€μž…μœΌλ‘œ 속성을 μΆ”κ°€ν•˜λ €λ©΄ 객체 μ „κ°œ({...a, ...b})λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

λ³€μˆ˜μ˜ 값은 변경될 수 μžˆμ§€λ§Œ νƒ€μž…μ€ 일반적으둜 λ³€κ²½λ˜μ§€ μ•ŠλŠ”λ‹€. 즉 객체λ₯Ό 생성할 λ•ŒλŠ” ν•˜λ‚˜μ”© μΆ”κ°€ν•˜κΈ°λ³΄λ‹€λŠ” μ—¬λŸ¬ 속성을 ν¬ν•¨ν•΄μ„œ ν•œκΊΌλ²ˆμ— 생성해야 νƒ€μž… 좔둠에 μœ λ¦¬ν•˜λ‹€.

const pt = {}  
pt.x = 3  
// ~ Property 'x' does not exist on type '{}'  
pt.y = 4  
// ~ Property 'y' does not exist on type '{}'
interface Point {  
  x: number  
  y: number  
}  
const pt:Point = {  
  x: 3,  
  y: 4,  
} // OK

ν˜Ήμ€ 객체 μ „κ°œ μ—°μ‚°μžλ₯Ό 톡해 ν•œκΊΌλ²ˆμ— λ§Œλ“€μ–΄ λ‚Ό 수 μžˆλ‹€.

const pt = { x: 3, y: 4 }  
const id = { name: 'Pythagoras' }  
const namedPoint = { ...pt, ...id }  
namedPoint.name // OK, type is string

μ•„μ΄ν…œ 24 일관성 μžˆλŠ” 별칭 μ‚¬μš©ν•˜κΈ°

별칭은 νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ νƒ€μž…μ„ μ’νžˆλŠ” 것을 λ°©ν•΄ν•œλ‹€. λ”°λΌμ„œ λ³€μˆ˜μ— 별칭을 μ‚¬μš©ν•  λ•ŒλŠ” μΌκ΄€λ˜κ²Œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€..

const borough = { name: 'Brooklyn', location: [40.688, -73.979] }  
const loc = borough.location;

borough.location 배열에 loc μ΄λΌλŠ” 별칭(alias)을 λ§Œλ“€μ—ˆλ‹€. λ³„μΉ­μ˜ 값을 λ³€κ²½ν•˜λ©΄ μ›λž˜ μ†μ„±κ°’μ—μ„œλ„ λ³€κ²½λœλ‹€.

별칭을 λ‚¨λ°œν•΄μ„œ μ‚¬μš©ν•˜λ©΄ μ œμ–΄ 흐름을 λΆ„μ„ν•˜κΈ° μ–΄λ ΅λ‹€.

비ꡬ쑰화 문법을 μ‚¬μš©ν•΄μ„œ μΌκ΄€λœ 이름을 μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

interface Coordinate {  
  x: number  
  y: number  
}  
  
interface BoundingBox {  
  x: [number, number]  
  y: [number, number]  
}  
  
interface Polygon {  
  exterior: Coordinate[]  
  holes: Coordinate[][]  
  bbox?: BoundingBox  
}
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {  
  const { bbox } = polygon  
  if (bbox) {  
    const { x, y } = bbox  
    if (pt.x < x[0] || pt.x > x[1] || pt.y < x[0] || pt.y > y[1]) {  
      return false  
    }  
  }  
  // ...  
}

ꡬ쑰뢄해할당을 ν†΅ν•΄μ„œ μΌκ΄€μ„±μžˆλŠ” 이름을 μ‚¬μš©ν•˜μž.

μ•„μ΄ν…œ 25 비동기 μ½”λ“œμ—λŠ” 콜백 λŒ€μ‹  async ν•¨μˆ˜ μ‚¬μš©ν•˜κΈ°

μ½œλ°±λ³΄λ‹€λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•˜λŠ”κ²Œ μ½”λ“œ μž‘μ„±κ³Ό νƒ€μž… μΆ”λ‘ λ©΄μ—μ„œ μœ λ¦¬ν•˜λ‹€.

μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  • μ½œλ°±λ³΄λ‹€λŠ” ν”„λ‘œλ―ΈμŠ€κ°€ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κΈ° 쉽닀.
  • μ½œλ°±λ³΄λ‹€λŠ” ν”„λ‘œλ―ΈμŠ€κ°€ νƒ€μž…μ„ μΆ”λ‘ ν•˜κΈ° 쉽닀.

κ°€λŠ₯ν•˜λ©΄ ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒμ„±ν•˜κΈ°λ³΄λ‹€λŠ” async와 awaitλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€. κ°„κ²°ν•˜κ³  직관적인 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 있고 λͺ¨λ“  μ’…λ₯˜μ˜ 였λ₯˜λ₯Ό μ œκ±°ν•  수 μžˆλ‹€.

κ·ΈλŸ¬λ‚˜ μΌλ°˜μ μœΌλ‘œλŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒμ„±ν•˜κΈ°λ³΄λ‹€λŠ” async/awaitλ₯Ό μ‚¬μš©ν•˜μž.

μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  • 일반적으둜 더 κ°„κ²°ν•˜κ³  직관적인 μ½”λ“œκ°€ λœλ‹€.
  • async ν•¨μˆ˜λŠ” 항상 ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ κ°•μ œλœλ‹€.
// function getNumber(): Promise<number>  
async function getNumber() {  
  return 42  
}

μ–΄λ–€ ν•¨μˆ˜κ°€ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€λ©΄ async둜 μ„ μ–Έν•˜λŠ” 것이 μ’‹λ‹€.

μ¦‰μ‹œ μ‚¬μš© κ°€λŠ₯ν•œ 값에도 ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ”κ²Œ μ΄μƒν•˜κ²Œ 보일 수 μžˆμ§€λ§Œ, μ‹€μ œλ‘œλŠ” 비동기 ν•¨μˆ˜λ‘œ ν†΅μΌν•˜λ„λ‘ κ°•μ œν•˜λŠ”λ° λ„μŒμ΄ λœλ‹€.

⚠️ **GitHub.com Fallback** ⚠️