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

μ•„μ΄ν…œ 51 μ˜μ‘΄μ„± 뢄리λ₯Ό μœ„ν•΄ 미러 νƒ€μž…μ„ μ‚¬μš©ν•˜κΈ°

ν•„μˆ˜κ°€ μ•„λ‹Œ μ˜μ‘΄μ„±μ„ 뢄리할 λ•ŒλŠ” ꡬ쑰적타이핑을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.

CSV νŒŒμΌμ„ νŒŒμ‹±ν•˜λŠ” 라이브러리λ₯Ό μž‘μ„±ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

CSV 파일의 λ‚΄μš©μ„ λ§€κ°œλ³€μˆ˜λ‘œ λ°›κ³  μ—΄ 이름을 κ°’μœΌλ‘œ λ§€ν•‘ν•˜λŠ” 객체듀을 μƒμ„±ν•˜μ—¬ λ°°μ—΄λ‘œ λ°˜ν™˜ν•œλ‹€. 그리고 NodeJS μ‚¬μš©μžλ₯Ό μœ„ν•΄ λ§€κ°œλ³€μˆ˜μ— Buffer νƒ€μž…μ„ ν—ˆμš©ν•œλ‹€.

function parseCSV(contents: string | Buffer): { [column: string]: string }[] {  
  if (typeof contents === 'object') {  
    // It's a buffer  
    return parseCSV(contents.toString('utf8'))  
  }  // COMPRESS  
  return []  
  // END  
}

Buffer νƒ€μž…μ€ npm install --save-dev @types/node λ₯Ό 톡해 얻을 수 μžˆλ‹€.

κ·ΈλŸ¬λ‚˜ @types/nodeλ₯Ό devDependencies둜 ν¬ν•¨ν•˜λ©΄ λ‹€μŒ 두 그룹의 라이브러리 μ‚¬μš©μžλ“€μ—κ²Œ λ¬Έμ œκ°€ 생긴닀.

  • @types와 λ¬΄κ΄€ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ 개발자
  • NodeJS와 λ¬΄κ΄€ν•œ νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ›Ή 개발자

κ°μžκ°€ ν•„μš”ν•œ λͺ¨λ“ˆλ§Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ ꡬ쑰적타이핑을 μ μš©ν•  수 μžˆλ‹€.

interface CsvBuffer {  
  toString(encoding: string): string  
}  
function parseCSV(contents: string | CsvBuffer): { [column: string]: string }[] {  
  // COMPRESS  
  return []  
  // END  
}

CsvBuffer λŠ” Buffer μΈν„°νŽ˜μ΄μŠ€λ³΄λ‹€ 훨씬 μ§§μœΌλ©΄μ„œλ„ μ‹€μ œλ‘œ ν•„μš”ν•œ λΆ€λΆ„λ§Œμ„ λ–Όμ–΄ λ‚΄μ–΄ λͺ…μ‹œν–ˆλ‹€. λ˜ν•œ ν•΄λ‹Ή νƒ€μž…μ΄ Buffer와 ν˜Έν™˜λ˜κΈ° λ•Œλ¬Έμ— NodeJS ν”„λ‘œμ νŠΈμ—μ„œλŠ” μ‹€μ œ Buffer μΈμŠ€ν„΄μŠ€λ‘œ parseCSVλ₯Ό ν˜ΈμΆœν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.

κ³΅κ°œν•œ 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ μ‚¬μš©μžκ°€ @types μ˜μ‘΄μ„±μ„ κ°€μ§€μ§€ μ•Šκ²Œ ν•΄μ•Ό ν•œλ‹€. 그리고 μ›Ή κ°œλ°œμžκ°€ NodeJS κ΄€λ ¨λœ μ˜μ‘΄μ„±μ„ κ°€μ§€μ§€ μ•Šκ²Œ ν•΄μ•Ό ν•œλ‹€.

λ§Œμ•½ μž‘μ„±μ€‘μΈ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ˜μ‘΄ν•˜λŠ” 라이브러리의 κ΅¬ν˜„κ³Ό λ¬΄κ΄€ν•˜κ²Œ νƒ€μž…μ—λ§Œ μ˜μ‘΄ν•œλ‹€λ©΄, ν•„μš”ν•œ μ„ μ–ΈλΆ€λ§Œ μΆ”μΆœν•˜μ—¬ μž‘μ„±μ€‘μΈ λΌμ΄λΈŒλŸ¬λ¦¬μ— λ„£λŠ” 것(미러링 , mirroring)을 κ³ λ €ν•΄λ³΄λŠ” 것도 μ’‹λ‹€.

NodeJS 기반 νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ‚¬μš©μžμ—κ²ŒλŠ” λ³€ν™”κ°€ μ—†μ§€λ§Œ, μ›Ή κΈ°λ°˜μ΄λ‚˜ μžλ°”μŠ€ν¬λ¦½νŠΈ λ“± λ‹€λ₯Έ λͺ¨λ“  μ‚¬μš©μžμ—κ²ŒλŠ” 더 λ‚˜μ€ 사양을 μ œκ³΅ν•  수 μžˆλ‹€.

λ‹€λ₯Έ 라이브러리의 νƒ€μž…μ΄ μ•„λ‹Œ κ΅¬ν˜„μ— μ˜μ‘΄ν•˜λŠ” κ²½μš°μ—λ„ λ™μΌν•œ 기법을 μ μš©ν•  수 있고 νƒ€μž…μ˜μ‘΄μ„±μ„ ν”Όν•  수 μžˆλ‹€. κ·ΈλŸ¬λ‚˜ ν”„λ‘œμ νŠΈμ˜ μ˜μ‘΄μ„±μ΄ λ‹€μ–‘ν•΄μ§€κ³  ν•„μˆ˜ μ˜μ‘΄μ„±μ΄ 좔가됨에 따라 λ―ΈλŸ¬λ§κΈ°λ²•μ„ μ μš©ν•˜κΈ° μ–΄λ €μ›Œμ§„λ‹€.

λ‹€λ₯Έ 라이브러리의 νƒ€μž… μ„ μ–Έμ˜ λŒ€λΆ€λΆ„μ„ μΆ”μΆœν•΄μ•Ό ν•œλ‹€λ©΄, 차라리 λͺ…μ‹œμ μœΌλ‘œ @types μ˜μ‘΄μ„±μ„ μΆ”κ°€ν•˜λŠ” 게 λ‚«λ‹€.

μ•„μ΄ν…œ 52 ν…ŒμŠ€νŒ… νƒ€μž…μ˜ 함정 μ£Όμ˜ν•˜κΈ°

νƒ€μž…μ„ ν…ŒμŠ€νŠΈν•  λ•ŒλŠ” 특히 ν•¨μˆ˜ νƒ€μž…μ˜ 동일성(equality)κ³Ό ν• λ‹Ή κ°€λŠ₯μ„± (assignability) 의 차이점을 μ•Œκ³  μžˆμ–΄μ•Ό ν•œλ‹€.

νƒ€μž… 선언도 ν…ŒμŠ€νŠΈλ₯Ό 거쳐야 ν•œλ‹€. κ·ΈλŸ¬λ‚˜ νƒ€μž… 선언을 ν…ŒμŠ€νŠΈν•˜κΈ°λŠ” 맀우 μ–΄λ ΅λ‹€.

κ·Έλž˜μ„œ νƒ€μž… 선언에 λŒ€ν•œ ν…ŒμŠ€νŠΈμ½”λ“œλ₯Ό μž‘μ„±ν•  λ•Œ νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ μ œκ³΅ν•˜λŠ” 도ꡬλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹¨μ–Έλ¬ΈμœΌλ‘œ λ•Œμš°κΈ° μ‹­μƒμ΄μ§€λ§Œ, 이런 λ°©λ²•μ—λŠ” λͺ‡ κ°€μ§€ λ¬Έμ œκ°€ μžˆλ‹€.

κΆκ·Ήμ μœΌλ‘œλŠ” dtslint λ˜λŠ” νƒ€μž… μ‹œμŠ€ν…œ μ™ΈλΆ€μ—μ„œ νƒ€μž…μ„ κ²€μ‚¬ν•˜λŠ” μœ μ‚¬ν•œ 도ꡬλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 더 μ•ˆμ „ν•˜κ³  κ°„λ‹¨ν•˜λ‹€.

μœ ν‹Έλ¦¬ν‹° λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ μ œκ³΅ν•˜λŠ” map ν•¨μˆ˜μ˜ νƒ€μž… 선언을 μž‘μ„±ν•œλ‹€κ³  κ°€μ •

declare function map<U, V>(array: U[], fn: (u: U) => V): V[]

νƒ€μž… 선언이 μ˜ˆμƒν•œ νƒ€μž…μœΌλ‘œ κ²°κ³Όλ₯Ό λ‚΄λŠ”μ§€ 체크할 수 μžˆλŠ” ν•œ κ°€μ§€ 방법은 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” ν…ŒμŠ€νŠΈ νŒŒμΌμ„ μž‘μ„±ν•˜λŠ” 것이닀. (κ΅¬ν˜„μ²΄λ₯Ό μœ„ν•œ λ³„λ„μ˜ ν…ŒμŠ€νŠΈλŠ” μžˆλ‹€κ³  κ°€μ •)

map(['2017', '2018', '2019'], v => Number(v))

이 μ½”λ“œλŠ” 였λ₯˜ 체크λ₯Ό μˆ˜ν–‰ν•˜μ§€λ§Œ ν—ˆμ μ΄ μ‘΄μž¬ν•œλ‹€.

예λ₯Ό λ“€μ–΄ map의 첫 번째 λ§€κ°œλ³€μˆ˜μ— 배열이 μ•„λ‹Œ 단일 값이 μžˆμ—ˆλ‹€λ©΄ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ— λŒ€ν•œ 였λ₯˜λŠ” μž‘μ„ 수 μžˆλ‹€. κ·ΈλŸ¬λ‚˜ λ°˜ν™˜κ°’μ— λŒ€ν•œ 체크가 λˆ„λ½λ˜μ–΄ 있기 λ•Œλ¬Έμ— μ™„μ „ν•œ ν…ŒμŠ€νŠΈλΌκ³  ν•  수 μ—†λ‹€.

콜백이 μžˆλŠ” ν•¨μˆ˜λ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ, 콜백 λ§€κ°œλ³€μˆ˜μ˜ μΆ”λ‘ λœ νƒ€μž…μ„ 체크해야 ν•œλ‹€. λ˜ν•œ thisκ°€ API의 일뢀뢄이라면 μ—­μ‹œ ν…ŒμŠ€νŠΈν•΄μ•Ό ν•œλ‹€.

λ°˜ν™˜κ°’μ„ νŠΉμ • νƒ€μž…μ˜ λ³€μˆ˜μ— ν• λ‹Ήν•˜μ—¬ κ°„λ‹¨νžˆ λ°˜ν™˜ νƒ€μž…μ„ 체크할 수 μžˆλŠ” 방법을 μ•Œμ•„λ³΄μž.

declare function map<U, V>(array: U[], fn: (u: U) => V): V[]  
const lengths: number[] = map(['john', 'paul'], name => name.length)

이 μ½”λ“œλŠ” 일반적으둜 λΆˆν•„μš”ν•œ νƒ€μž… 선언에 ν•΄λ‹Ήν•œλ‹€. κ·ΈλŸ¬λ‚˜ ν…ŒμŠ€νŠΈ μ½”λ“œ κ΄€μ μ—μ„œλŠ” μ€‘μš”ν•œ 역할을 ν•˜κ³  μžˆλ‹€.

number[] νƒ€μž… 선언은 map ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ΄ number[]μž„μ„ 보μž₯ν•œλ‹€.

νƒ€μž… κ΄€λ ¨λœ ν…ŒμŠ€νŠΈμ—μ„œ anyλ₯Ό μ£Όμ˜ν•΄μ•Ό ν•œλ‹€. 더 μ—„κ²©ν•œ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ dtslint같은 도ꡬλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

declare module 'overbar';

이 선언은 전체 λͺ¨λ“ˆμ— any νƒ€μž…μ„ ν• λ‹Ήν•œλ‹€. λ”°λΌμ„œ ν…ŒμŠ€νŠΈλŠ” μ „λΆ€ ν†΅κ³Όν•˜κ² μ§€λ§Œ, λͺ¨λ“  νƒ€μž… μ•ˆμ „μ„±μ„ ν¬κΈ°ν•˜κ²Œ λœλ‹€. 더 λ‚˜μœ 점은, ν•΄λ‹Ή λͺ¨λ“ˆμ— μ†ν•˜λŠ” λͺ¨λ“  ν•¨μˆ˜μ˜ν˜ΈμΆœλ§ˆλ‹€ μ•”μ‹œμ μœΌλ‘œ any νƒ€μž…μ„ λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ— μ½”λ“œ μ „λ°˜μ— 걸쳐 νƒ€μž… μ•ˆμ „μ„±μ„ μ§€μ†μ μœΌλ‘œ λ¬΄λ„ˆλœ¨λ¦¬κ²Œ λœλ‹€λŠ” 것이닀.

noImplicitAnyλ₯Ό μ„€μ •ν•˜λ”λΌλ„ νƒ€μž… 선언을 톡해 μ—¬μ „νžˆ any νƒ€μž…μ΄ μƒκ²¨λ‚˜κ²Œ λœλ‹€. νƒ€μž… μ‹œμŠ€ν…œ λ‚΄μ—μ„œ μ•”μ‹œμ  anyνƒ€μž…μ„ λ°œκ²¬ν•΄ λ‚΄λŠ” 것은 맀우 μ–΄λ ΅λ‹€.

μ΄λŸ¬ν•œ 어렀움 λ•Œλ¬Έμ— νƒ€μž… 체컀와 λ…λ¦½μ μœΌλ‘œ λ™μž‘ν•˜λŠ” 도ꡬλ₯Ό μ‚¬μš©ν•΄μ„œ νƒ€μž… 선언을 ν…ŒμŠ€νŠΈ ν•˜λŠ” 방법이 ꢌμž₯λœλ‹€.

DefinitelyTyped 의 νƒ€μž… 선언을 μœ„ν•œ λ„κ΅¬λŠ” dtslint 이닀. dtslint λŠ” νŠΉλ³„ν•œ ν˜•νƒœμ˜ 주석을 톡해 λ™μž‘ν•œλ‹€.

declare function map<U, V>(array: U[], fn: (this: U[], u: U, i: number, array: U[]) => V): V[]  
const beatles = ['john', 'paul', 'george', 'ringo']  
map(  
  beatles,  
  function (  
    name, // $ExpectType string  
    i, // $ExpectType number  
    array, // $ExpectType string[]  
  ) {  
    this // $ExpectType string[]  
    return name.length  
  },  
) // $ExpectType number[]

dtslintλŠ” ν• λ‹Ή κ°€λŠ₯성을 μ²΄ν¬ν•˜λŠ” λŒ€μ‹  각 μ‹¬λ²Œμ˜ νƒ€μž…μ„ μΆ”μΆœν•˜μ—¬ κΈ€μž μžμ²΄κ°€ 같은지 λΉ„κ΅ν•œλ‹€.

μ•„μ΄ν…œ 53 νƒ€μž…μŠ€ν¬λ¦½νŠΈ κΈ°λŠ₯보닀 ECMAScript κΈ°λŠ₯을 μ‚¬μš©ν•˜κΈ°

일반적으둜 νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ½”λ“œμ—μ„œ λͺ¨λ“  νƒ€μž… 정보λ₯Ό μ œκ±°ν•˜λ©΄ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ λ˜μ§€λ§Œ, μ—΄κ±°ν˜•, λ§€κ°œλ³€μˆ˜ 속성, νŠΈλ¦¬ν”Œ μŠ¬λž˜μ‹œ μž„ν¬νŠΈ, λ°μ½”λ ˆμ΄ν„°λŠ” νƒ€μž… 정보λ₯Ό μ œκ±°ν•œλ‹€κ³  μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ λ˜μ§€λŠ” μ•ŠλŠ”λ‹€.

μ—΄κ±°ν˜•(enum)

λ§Žμ€ μ–Έμ–΄μ—μ„œ λͺ‡λͺ‡ κ°’μ˜ λͺ¨μŒμ„ λ‚˜νƒ€λ‚΄κΈ° μœ„ν•΄ μ—΄κ±°ν˜•μ„ μ‚¬μš©ν•œλ‹€. νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œλ„ μ—΄κ±°ν˜•μ„ μ‚¬μš©ν•  수 μžˆλ‹€.

enum Flavor {  
  VANILLA = 0,  
  CHOCOLATE = 1,  
  STRAWBERRY = 2,  
}  
  
let flavor = Flavor.CHOCOLATE // νƒ€μž…μ΄ Flavor  
  
Flavor // μžλ™μ™„μ„± μΆ”μ²œ: VANILLA, CHOCOLATE, STRAWBERRY  
Flavor[0] // 값이 "VANILLA"

κ·ΈλŸ¬λ‚˜ νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ μ—΄κ±°ν˜•μ€ λͺ‡ κ°€μ§€ λ¬Έμ œκ°€ μžˆλ‹€. νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ μ—΄κ±°ν˜•μ€ λ‹€μŒ λͺ©λ‘μ²˜λŸΌ 상황에 따라 λ™μž‘ν•œλ‹€.

  • 숫자 μ—΄κ±°ν˜•(μ•ž 예제의 Flavor)에 0, 1, 2 μ™Έμ˜ λ‹€λ₯Έ μˆ«μžκ°€ ν• λ‹Ήλ˜λ©΄ 맀우 μœ„ν—˜ν•˜λ‹€. ( 이 방법은 μ›λž˜ λΉ„νŠΈ ν”Œλž˜κ·Έ ꡬ쑰λ₯Ό ν‘œν˜„ν•˜κΈ° μœ„ν•΄ μ„€κ³„λ˜μ—ˆλ‹€. )
  • μƒμˆ˜ μ—΄κ±°ν˜•μ€ λ³΄ν†΅μ˜ μ—΄κ±°ν˜•κ³Ό 달리 λŸ°νƒ€μž„μ— μ™„μ „νžˆ μ œκ±°λœλ‹€. μ•žμ˜ 예제λ₯Ό const enum Flavor둜 λ°”κΎΈλ©΄ μ»΄νŒŒμΌλŸ¬λŠ” Flavor.CHOCOLATE을 0으둜 바꿔버린닀. 이런 κ²°κ³ΌλŠ” κΈ°λŒ€ν•˜μ§€ μ•Šμ€ 것이며, λ¬Έμžμ—΄ μ—΄κ±°ν˜•κ³Ό 숫자 μ—΄κ±°ν˜•κ³Ό μ „ν˜€ λ‹€λ₯Έ λ™μž‘μ΄λ‹€.
  • preserveConstEnums ν”Œλž˜κ·Έλ₯Ό μ„€μ •ν•œ μƒνƒœμ˜ μƒμˆ˜ μ—΄κ±°ν˜•μ€ λ³΄ν†΅μ˜ μ—΄κ±°ν˜•μ²˜λŸΌ λŸ°νƒ€μž„ μ½”λ“œμ— μƒμˆ˜ μ—΄κ±°ν˜• 정보λ₯Ό μœ μ§€ν•œλ‹€.
  • λ¬Έμžμ—΄ μ—΄κ±°ν˜•μ€ λŸ°νƒ€μž„μ˜ νƒ€μž… μ•ˆμ „μ„±κ³Ό 투λͺ…성을 μ œκ³΅ν•œλ‹€. κ·ΈλŸ¬λ‚˜ νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ λ‹€λ₯Έ ꡬ쑰적 타이핑이 μ•„λ‹Œ λͺ…λͺ©μ  타이핑을 μ‚¬μš©ν•œλ‹€.

λ§€κ°œλ³€μˆ˜ 속성

일반적으둜 클래슀λ₯Ό μ΄ˆκΈ°ν™”ν•  λ•Œ 속성을 ν• λ‹Ήν•˜κΈ° μœ„ν•΄ μƒμ„±μžμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•œλ‹€.

class Person {  
  name: string  
  constructor(name: string) {  
    this.name = name  
  }  
}

νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” 더 κ°„κ²°ν•œ 문법을 μ œκ³΅ν•œλ‹€.

class Person {  
  constructor(public name: string) {}  
}

예제의 public name 은 'λ§€κ°œλ³€μˆ˜ 속성' 이라고 뢈리며, 멀버 λ³€μˆ˜λ‘œ name을 μ„ μ–Έν•œ 이전 μ˜ˆμ œμ™€ λ™μΌν•˜κ²Œ λ™μž‘ν•œλ‹€.

κ·ΈλŸ¬λ‚˜ λ§€κ°œλ³€μˆ˜ 속성과 κ΄€λ ¨λœ λͺ‡ κ°€μ§€ 문제점이 μ‘΄μž¬ν•œλ‹€.

  • 일반적으둜 νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ»΄νŒŒμΌμ€ νƒ€μž… 체컀가 μ΄λ£¨μ–΄μ§€λ―€λ‘œ μ½”λ“œκ°€ μ€„μ–΄λ“€μ§€λ§Œ, λ§€κ°œλ³€μˆ˜ 속성은 μ½”λ“œκ°€ λŠ˜μ–΄λ‚˜λŠ” 문법이닀.
  • λ§€κ°œλ³€μˆ˜ 속성이 λŸ°νƒ€μž„μ—λŠ” μ‹€μ œλ‘œ μ‚¬μš©λ˜μ§€λ§Œ, νƒ€μž…μŠ€ν¬λ¦½νŠΈ κ΄€μ μ—μ„œλŠ” μ‚¬μš©λ˜μ§€ μ•ŠλŠ” κ²ƒμ²˜λŸΌ 보인닀.
  • λ§€κ°œλ³€μˆ˜ 속성과 일반 속성을 μ„žμ–΄μ„œ μ‚¬μš©ν•˜λ©΄ 클래슀의 섀계가 ν˜Όλž€μŠ€λŸ¬μ›Œμ§„λ‹€.

λ§€κ°œλ³€μˆ˜ 속성을 μ‚¬μš©ν•˜λŠ” 것이 쒋은지에 λŒ€ν•΄μ„œλŠ” 찬반 λ…Όλž€μ΄ μžˆλ‹€. κΈ€μ“΄μ΄λŠ” λ§€κ°œλ³€μˆ˜ 속성을 μ„ ν˜Έν•˜μ§€ μ•Šμ§€λ§Œ, μ–΄λ–€ 이듀은 μ½”λ“œμ–‘μ΄ 쀄어 λ“€μ–΄μ„œ μ’‹μ•„ν•˜κΈ°λ„ ν•œλ‹€.

λ„€μž„μŠ€νŽ˜μ΄μŠ€μ™€ νŠΈλ¦¬ν”Œ μŠ¬λž˜μ‹œ μž„ν¬νŠΈ

Node.js : require 와 module.exports 을 μ‚¬μš© AMD : define ν•¨μˆ˜μ™€ μ½œλ°±μ„ μ‚¬μš© νƒ€μž…μŠ€ν¬λ¦½νŠΈ : module ν‚€μ›Œλ“œ 와 'νŠΈλ¦¬ν”Œ μŠ¬λž˜μ‹œ' μž„ν¬νŠΈλ₯Ό μ‚¬μš©

ECMAScript2015 κ°€ κ³΅μ‹μ μœΌλ‘œ λͺ¨λ“ˆμ‹œμŠ€ν…œ 을 λ„μž…ν•œ 이후 νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” μΆ©λŒμ„ ν”Όν•˜κΈ° μœ„ν•΄ moduleκ³Ό 같은 κΈ°λŠ₯을 ν•˜λŠ” namespace ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν–ˆλ‹€.

namespace foo {  
  function bar() {}  
}

/// <reference path="oter.ts"/>
foo.bar();

νŠΈλ¦¬ν”ŒμŠ¬λž˜μ‹œμž„ν¬νŠΈ 와 module ν‚€μ›Œλ“œλŠ” ν˜Έν™˜μ„±μ„ μœ„ν•΄ λ‚¨μ•„μžˆμ„ 뿐이며, μ΄μ œλŠ” ECMAScript2015 μŠ€νƒ€μΌμ˜ λͺ¨λ“ˆ(import와 export)을 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ˜ 역할을 λͺ…ν™•ν•˜κ²Œ ν•˜λ €λ©΄, μ—΄κ±°ν˜•, λ§€κ°œλ³€μˆ˜ 속성, νŠΈλ¦¬ν”Œ μŠ¬λž˜μ‹œ μž„ν¬νŠΈ, λ°μ½”λ ˆμ΄ν„°λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€.

λ°μ½”λ ˆμ΄ν„° λŠ” μ²˜μŒμ— μ•΅κ·€λŸ¬ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ§€μ›ν•˜κΈ° μœ„ν•΄ μΆ”κ°€λ˜μ—ˆμœΌλ©° tscondig.json에 experimetalDecorators 속성을 μ„€μ •ν•˜κ³  μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

μ•΅κ·€λŸ¬λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ μ• λ„ˆν…Œμ΄μ…˜μ΄ ν•„μš”ν•œ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜κ³  μžˆλŠ”κ²Œ μ•„λ‹ˆλΌλ©΄, λ°μ½”λ ˆμ΄ν„°κ°€ ν‘œμ€€μ΄ 되기 μ „κΉŒμ§€λŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”κ²Œ μ’‹λ‹€.

μ•„μ΄ν…œ 54 객체λ₯Ό μˆœνšŒν•˜λŠ” λ…Έν•˜μš°

객체λ₯Ό μˆœνšŒν•  λ•Œ, ν‚€κ°€ μ–΄λ–€ νƒ€μž…μΈμ§€ μ •ν™•νžˆ νŒŒμ•…ν•˜κ³  μžˆλ‹€λ©΄ let k: keyof 와 for-in 루프λ₯Ό μ‚¬μš©ν•˜μž. ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ“°μ΄λŠ” κ°μ²΄μ—λŠ” 좔가적인 ν‚€κ°€ μ‘΄μž¬ν•  수 μžˆλ‹€λŠ” 점을 λͺ…μ‹¬ν•˜μž.

이해λ₯Ό 돕기 μœ„ν•΄ μΈν„°νŽ˜μ΄μŠ€μ™€ ν•¨μˆ˜κ°€ κ°€λ―Έλœ λ‹€λ₯Έ 예제λ₯Ό μ‚΄νŽ΄λ³΄μž.

interface ABC {  
  a: string  
  b: string  
  c: number  
}  
  
function foo(abc: ABC) {  
  for (const k in abc) {  
    // const k: string  
    const v = abc[k]  
    // ~~~~~~ Element implicitly has an 'any' type  
    //        because type 'ABC' has no index signature  }  
}

k 에 λŒ€ν•˜μ—¬ 였λ₯˜κ°€ λ°œμƒν–ˆλ‹€. 이와 같은 였λ₯˜λŠ” (let k: keyof ABC) 같은 μ„ μ–ΈμœΌλ‘œ 였λ₯˜λ₯Ό μ œκ±°ν•  수 μžˆλ‹€.

객체λ₯Ό μˆœνšŒν•˜λ©° 킀와 값을 μ–»λŠ” 일반적인 방법은 Object.entries λ₯Ό μ‚¬μš©ν•˜λŠ” 것이닀.

골치 μ•„ν”ˆ νƒ€μž… 문제 없이, 단지 객체의 킀와 값을 μˆœνšŒν•˜κ³  μ‹Άλ‹€λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒ? Object.entries λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

interface ABC {  
  a: string  
  b: string  
  c: number  
}  
function foo(abc: ABC) {  
  for (const [k, v] of Object.entries(abc)) {  
    k // Type is string  
    v // Type is any  
  }  
}

μ•„μ΄ν…œ 55 DOM 계측 ꡬ쑰 μ΄ν•΄ν•˜κΈ°

μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” μ‹ κ²½μ“°μ§€ μ•Šμ•˜κ² μ§€λ§Œ, DOMμ—λŠ” νƒ€μž… 계측 ꡬ쑰가 μžˆλ‹€. DOM νƒ€μž…μ€ νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ μ€‘μš”ν•œ 정보이며, λΈŒλΌμš°μ € κ΄€λ ¨ ν”„λ‘œμ νŠΈμ—μ„œ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•  λ•Œ μœ μš©ν•˜λ‹€.

Node, Element, HTMLElement, EventTarget κ°„μ˜ 차이점, Event와 MouseEvent 차이점을 μ•Œμ•„μ•Όν•œλ‹€.

λ‹€μŒ HTML μ½”λ“œλ₯Ό 보자.

<p id="quote">and <i>yet</i> it moves</p>

λΈŒλΌμš°μ €μ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½˜μ†”μ„ μ—΄κ³  p μ—˜λ¦¬λ¨ΌνŠΈμ˜ μ°Έμ‘°λ₯Ό μ–»μ–΄ 보면, HTMLParagraphElement νƒ€μž…μ΄λΌλŠ” 것을 μ•Œ 수 μžˆλ‹€.

const p = document.getElementByTagName('p')[0];
p instanceof HTMLParagraphElement
// μ°Έ true

HTMLParagraphElement λŠ” HTMLElement의 μ„œλΈŒνƒ€μž…μ΄κ³  HTMLElementλŠ” Element의 μ„œλΈŒ νƒ€μž…μ΄λ‹€. λ˜ν•œ ElementλŠ” Node의 μ„œλΈŒνƒ€μž…μ΄κ³  NodeλŠ” EventTarget의 μ„œλΈŒ νƒ€μž…μ΄λ‹€.

계측 ꡬ쑰에 λ”°λ₯Έ νƒ€μž…μ˜ λͺ‡ κ°€μ§€ μ˜ˆμ‹œ

νƒ€μž… μ˜ˆμ‹œ
EventTarget window, XMLHttpRequest
Node document, Text, Comment
Element HTMLElement, SVGElement 포함
HTMLElement <i>, <b>
HTMLButtonElement <button>

DOM μ—˜λ¦¬λ¨ΌνŠΈμ™€ μ΄λ²€νŠΈμ—λŠ” μΆ©λΆ„νžˆ ꡬ체적인 νƒ€μž… 정보λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜, νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ μΆ”λ‘ ν•  수 μžˆλ„λ‘ λ¬Έλ§₯ 정보λ₯Ό ν™œμš©ν•΄μ•Ό ν•œλ‹€.

보톡은 HTML νƒœκ·Έ 값에 ν•΄λ‹Ήν•˜λŠ” 'button' 같은 λ¦¬ν„°λŸ΄ 값을 μ‚¬μš©ν•˜μ—¬ DOM에 λŒ€ν•œ μ •ν™•ν•œ νƒ€μž…μ„ 얻을 수 μžˆλ‹€. 예λ₯Ό λ“€λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

document.getElementsByTagName('p')[0] // HTMLParagraphElement  
document.createElement('button') // HTMLButtonElement  
document.querySelector('div') // HTMLDivElement

κ·ΈλŸ¬λ‚˜ 항상 μ •ν™•ν•œ νƒ€μž…μ„ 얻을 수 μžˆλŠ” 것은 μ•„λ‹ˆλ‹€. 특히 document.getElementByIdμ—μ„œ λ¬Έμ œκ°€ λ°œμƒν•˜κ²Œ λœλ‹€.

document.getElementById('my-div') // HTMLElement

일반적으둜 νƒ€μž… 단언문은 μ§€μ–‘ν•΄μ•Όν•˜μ§€λ§Œ DOM κ΄€λ ¨ν•΄μ„œλŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈλ³΄λ‹€ μš°λ¦¬κ°€ 더 μ •ν™•νžˆ μ•Œκ³  μžˆλŠ” κ²½μš°μ΄λ―€λ‘œ 단언문을 μ‚¬μš©ν•΄λ„ μ’‹λ‹€.

#my-div κ°€ div νƒœκ·ΈλΌλŠ” 것을 μ•Œκ³ μžˆμœΌλ―€λ‘œ λ¬Έμ œκ°€ λ˜μ§€ μ•ŠλŠ”λ‹€.

document.getElementById('my-div') as HTMLDivElement

stritNullChecksκ°€ μ„€μ •λœ μƒνƒœλΌλ©΄, document.getElementByIdκ°€ null인 경우λ₯Ό μ²΄ν¬ν•΄μ•Όν•œλ‹€. μ‹€μ œ μ½”λ“œμ—μ„œ document.getElementByIdκ°€ null일 κ°€λŠ₯성이 μžˆλ‹€λ©΄ if 뢄기문을 μΆ”κ°€ν•˜λ„λ‘ ν•˜μž.

document.getElementById('my-div')!;

EventTarget μ΄ν›„μ—λŠ” λ‹€μŒ 였λ₯˜κ°€ λ°œμƒν–ˆλ‹€. 였λ₯˜μ˜ 원인을 μ‚΄νŽ΄λ³΄μž.

function handleDrag(eDown: Event) {  
  // ...  
  const dragStart = [eDown.clientX, eDown.clientY]  
  // ~~~~~~~                Property 'clientX' does not exist on 'Event'  
  //                ~~~~~~~ Property 'clientY' does not exist on 'Event'  // ...}

ν‘œμ—μ„œ μ‚΄νŽ΄λ΄€λ˜ EventTarget νƒ€μž…μ˜ 계측 ꡬ쑰뿐 μ•„λ‹ˆλΌ, Event νƒ€μž…μ—λ„ λ³„λ„μ˜ 계측 ꡬ쑰가 μžˆλ‹€. Mozilla λ¬Έμ„œμ—λŠ” 52개 μ΄μƒμ˜ Event μ’…λ₯˜κ°€ λ‚˜μ—΄λ˜μ–΄ μžˆλ‹€.

EventλŠ” κ°€μž₯ μΆ”μƒν™”λœ μ΄λ²€νŠΈμ΄λ‹€. 더 ꡬ체적인 νƒ€μž…λ“€μ€ λ‹€μŒκ³Ό κ°™λ‹€.

  • UIEvent : λͺ¨λ“  μ’…λ₯˜μ˜ μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ 이벀트
  • MouseEvent : 클릭처럼 λ§ˆμš°μŠ€λ‘œλΆ€ν„° λ°œμƒλ˜λŠ” 이벀트
  • TouchEvent : λͺ¨λ°”일 기기의 ν„°μΉ˜ 이벀트
  • WheelEvent : 슀크둀 νœ μ„ λŒλ €μ„œ λ°œμƒλ˜λŠ” 이벀트
  • KeyboardEvent : ν‚€ λˆ„λ¦„ 이벀트

clientX, clientY μ—μ„œ λ°œμƒν•œ 였λ₯˜μ˜ 원인은, handleDrag ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λŠ” Event둜 μ„ μ–Έλœ 반면 clientX, clientY 보닀 ꡬ체적인 MouseEvent νƒ€μž…μ— 있기 λ•Œλ¬Έμ΄λ‹€.

'mousedown' 이벀트 ν•Έλ“€λŸ¬λ₯Ό 인라인 ν•¨μˆ˜λ‘œ λ§Œλ“€λ©΄ νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” 더 λ§Žμ€ λ¬Έλ§₯ 정보λ₯Ό μ‚¬μš©ν•˜κ²Œ 되고, λŒ€λΆ€λΆ„μ˜ 였λ₯˜λ₯Ό μ œκ±°ν•  수 μžˆλ‹€.

λ˜ν•œ λ§€κ°œλ³€μˆ˜ νƒ€μž…μ„ Event λŒ€μ‹  MouseEvent 둜 μ„ μ–Έν•  수 μžˆλ‹€.

λ‹€μŒ μ˜ˆμ œλŠ” 방금 μ–ΈκΈ‰ν•œ 인라인 ν•¨μˆ˜μ™€ 이벀트 νƒ€μž… 변경을 μ μš©ν•΄μ„œ 였λ₯˜λ₯Ό μ œκ±°ν•œ μ½”λ“œμ΄λ‹€.

function addDragHandler(el: HTMLElement) {  
  el.addEventListener('mousedown', eDown => {  
    const dragStart = [eDown.clientX, eDown.clientY]  
    const handleUp = (eUp: MouseEvent) => {  
      el.classList.remove('dragging')  
      el.removeEventListener('mouseup', handleUp)  
      const dragEnd = [eUp.clientX, eUp.clientY]  
      console.log(  
        'dx, dy = ',  
        [0, 1].map(i => dragEnd[i] - dragStart[i]),  
      )  
    }  
    el.addEventListener('mouseup', handleUp)  
  })  
}

μ•„μ΄ν…œ 56 정보λ₯Ό κ°μΆ”λŠ” λͺ©μ μœΌλ‘œ private μ‚¬μš©ν•˜μ§€ μ•ŠκΈ°

public, protected, private μ ‘κ·Ό μ œμ–΄μžλŠ” νƒ€μž… μ‹œμŠ€ν…œμ—μ„œλ§Œ κ°•μ œλ  뿐이닀. λŸ°νƒ€μž„μ—λŠ” μ†Œμš©μ΄ μ—†μœΌλ©° 단언문을 톡해 μš°νšŒν•  수 μžˆλ‹€. μ ‘κ·Ό μ œμ–΄μžλ‘œ 데이터λ₯Ό 감좔렀고 ν•΄μ„œλŠ” μ•ˆλœλ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν΄λž˜μŠ€μ— λΉ„κ³΅κ°œ 속성을 λ§Œλ“€ 수 μ—†λ‹€. λ§Žμ€ 이가 λΉ„κ³΅κ°œμ†μ„±μž„μ„ λ‚˜νƒ€λ‚΄κΈ° μœ„ν•΄ μ–Έλ”μŠ€μ½”μ–΄ _ λ₯Ό μ ‘λ‘μ‚¬λ‘œ λΆ™μ΄λ˜ 것이 κ΄€λ‘€λ‘œ 인정될 λΏμ΄μ—ˆλ‹€.

class Foo {
	_private = 'secret123';
}

κ·ΈλŸ¬λ‚˜ 속성에 μ–Έλ”μŠ€μ½”μ–΄λ₯Ό λΆ™μ΄λŠ” 것은 λ‹¨μˆœν•œ λΉ„κ³΅κ°œλΌκ³  ν‘œμ‹œν•œ 것뿐이닀. λ”°λΌμ„œ 일반적인 속성과 λ™μΌν•˜κ²Œ 클래슀 μ™ΈλΆ€λ‘œ κ³΅κ°œλ˜μ–΄ μžˆλ‹€λŠ” 점을 μ£Όμ˜ν•΄μ•Όν•œλ‹€.

const f = new Foo();
f._private; // 'secret123'

νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—λŠ” public, protected, private μ ‘κ·Ό μ œμ–΄μžλ₯Ό μ‚¬μš©ν•΄μ„œ κ³΅κ°œκ·œμΉ™μ„ κ°•μ œν•˜λŠ” κ²ƒμœΌλ‘œ μ˜€ν•΄ν•  수 μžˆλ‹€.

class Diary {  
  private secret = 'cheated on my English test'  
}  
  
const diary = new Diary()  
diary.secret  
// ~~~~~~ Property 'secret' is private and only  
//        accessible within class 'Diary'

κ·ΈλŸ¬λ‚˜ public, protected, private 같은 μ ‘κ·Όμ œμ–΄μžλŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈ ν‚€μ›Œλ“œμ΄κΈ° λ•Œλ¬Έμ— 컴파일 ν›„μ—λŠ” μ œκ±°λœλ‹€

ν™•μ‹€νžˆ 데이터λ₯Ό 감좔고 μ‹Άλ‹€λ©΄ ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•΄μ•Όν•œλ‹€.

declare function hash(text: string): number  
  
class PasswordChecker_ {  
  checkPassword: (password: string) => boolean  
  constructor(passwordHash: number) {  
    this.checkPassword = (password: string) => {  
      return hash(password) === passwordHash  
    }  
  }  
}  
  
const checker = new PasswordChecker(hash('s3cret'))  
checker.checkPassword('s3cret') // Returns true

μ•žμ˜ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ PasswordChecker의 μƒμ„±μž μ™ΈλΆ€μ—μ„œ passwordHash λ³€μˆ˜μ— μ ‘κ·Όν•  수 μ—†κΈ° λ•Œλ¬Έμ— 정보λ₯Ό μˆ¨κΈ°λŠ” λͺ©μ μ„ λ‹¬μ„±ν–ˆλ‹€.

class PasswordChecker {
	#passwordHash: number;
	constructor(passwordHash: number) {
		this.#passwordHash = passwordHash;
	}
	checkPassword(password: string) {
		return hash(password) === this.#passwordHash;
	}
}

const checker = new PasswordChecker(hash('s3cret'));
checker.checkPassword('secret'); // false
checker.checkPassword('s3cret'); // true

ν˜Ήμ€ 접두사 # 을 λΆ™μ—¬μ„œ νƒ€μž… 체크와 λŸ°νƒ€μž„ λͺ¨λ‘μ—μ„œ λΉ„κ³΅κ°œλ‘œ λ§Œλ“œλŠ” 역할을 ν•œλ‹€.

λ§Œμ•½ 섀계 κ΄€μ μ˜ μΊ‘μŠν™”κ°€ μ•„λ‹Œ 'λ³΄μ•ˆ'에 λŒ€ν•΄ κ±±μ •ν•˜κ³  μžˆλ‹€λ©΄, λ‚΄μž₯된 ν”„λ‘œν† νƒ€μž… ν•¨μˆ˜μ— λŒ€ν•œ λ³€μ‘° 같은 문제λ₯Ό μ•Œκ³  μžˆμ–΄μ•Ό ν•œλ‹€.

μ•„μ΄ν…œ 57 μ†ŒμŠ€λ§΅μ„ μ‚¬μš©ν•˜μ—¬ νƒ€μž…μŠ€ν¬λ¦½νŠΈ λ””λ²„κΉ…ν•˜κΈ°

원본 μ½”λ“œκ°€ μ•„λ‹Œ λ³€ν™˜λœ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό λ””λ²„κΉ…ν•˜μ§€ 말자. μ†ŒμŠ€λ§΅μ„ μ‚¬μš©ν•΄μ„œ λŸ°νƒ€μž„μ— νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό λ””λ²„κΉ…ν•˜μž. λ˜ν•œ, μ†ŒμŠ€λ§΅μ΄ μ΅œμ’…μ μœΌλ‘œ λ³€ν™˜λœ μ½”λ“œμ— μ™„μ „νžˆ λ§€ν•‘λ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜μž.

νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό μ‹€ν–‰ν•œλ‹€λŠ” 것은, μ—„λ°€νžˆ λ§ν•˜μžλ©΄ νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ»΄νŒŒμΌλŸ¬κ°€ μƒμ„±ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό μ‹€ν–‰ν•œλ‹€λŠ” 것이닀.

사싀 컴파일러뿐 μ•„λ‹ˆλΌ μ••μΆ•κΈ°(minifier)λ‚˜ μ „μ²˜λ¦¬κΈ°(preprocessor)처럼, κΈ°μ‘΄ μ½”λ“œλ₯Ό λ‹€λ₯Έ ν˜•νƒœμ˜ μ½”λ“œλ‘œ λ³€ν™˜ν•˜λŠ” λ„κ΅¬λ“€μ—κ²Œλ„ λͺ¨λ‘ ν•΄λ‹Ήλœλ‹€.

μ΄λŸ¬ν•œ λ³€ν˜Έλ‚˜ 과정듀이 투λͺ…ν•˜κ³  직관적이라면 이상적일 것이닀. μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³Ό ν•„μš” 없이 마치 νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ½”λ“œκ°€ 직접 μ‹€ν–‰λ˜λŠ” κ²ƒμ²˜λŸΌ λŠκ»΄μ§„λ‹€λ©΄ 말이닀.

ν•˜μ§€λ§Œ ν˜„μ‹€μ€ κ·Έλ ‡μ§€ λͺ»ν•˜λ‹€.

디버깅이 ν•„μš”ν•œ μ‹œμ μ— λΉ„λ‘œμ†Œ νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ 직접 μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌλŠ” 사싀을 κΉ¨λ‹«κ²Œ 될것이닀.

λ””λ²„κ±°λŠ” λŸ°νƒ€μž„μ— λ™μž‘ν•˜λ©°, ν˜„μž¬ λ™μž‘ν•˜λŠ” μ½”λ“œκ°€ μ–΄λ–€ 과정을 κ±°μ³μ„œ λ§Œλ“€μ–΄μ§„ 것인지 μ•Œμ§€ λͺ»ν•œλ‹€. 디버깅을 ν•˜λ©΄ λ³΄κ²Œλ˜λŠ” μ½”λ“œλŠ” μ „μ²˜λ¦¬κΈ°, 컴파일러, μ••μΆ•κΈ°λ₯Ό 거친 μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œμΌ 것이닀.

μ΄λ ‡κ²Œ λ³€ν™˜λœ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλŠ” λ³΅μž‘ν•΄ λ””λ²„κΉ…ν•˜κΈ° 맀우 μ–΄λ ΅λ‹€.

디버깅 문제λ₯Ό ν•΄κ²°ν•˜κΈ°μœ„ν•΄ λΈŒλΌμš°μ € μ œμ‘°μ‚¬λ“€μ€ μ„œλ‘œ ν˜‘λ ₯ν•˜μ—¬ μ†ŒμŠ€λ§΅ μ΄λΌλŠ” 해결책을 λ‚΄λ†“μ•˜λ‹€.

μ†ŒμŠ€λ§΅μ€ λ³€ν™˜λœ μ½”λ“œμ˜ μœ„μΉ˜μ™€ μ‹¬λ²Œλ“€μ„ 원본 μ½”λ“œμ˜ μ›λž˜ μœ„μΉ˜μ™€ μ‹¬λ²Œλ“€λ‘œ λ§€ν•‘ν•œλ‹€. λŒ€λΆ€λΆ„μ˜ λΈŒλΌμš°μ €μ™€ λ§Žμ€ IDEκ°€ μ†ŒμŠ€λ§΅μ„ μ§€μ›ν•œλ‹€.

μ½”λ“œκ°€ λ³΅μž‘ν•˜κ²Œ λ³€ν™˜λœλ‹€λ©΄ μ†ŒμŠ€λ§΅μ΄ ν•„μš”ν•˜λ‹€. νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ μ†ŒμŠ€λ§΅μ„ 생성할 수 μžˆλ„λ‘ tsconfig.json μ—μ„œ sourceMap μ˜΅μ…˜μ„ μ„€μ •ν•˜λ©΄ ts νŒŒμΌμ— λŒ€ν•΄μ„œ .js .js.map 두 개의 νŒŒμΌμ„ μƒμ„±ν•œλ‹€.

.js.map 파일이 λ°”λ‘œ μ†ŒμŠ€λ§΅μ΄λ‹€.

μ†ŒμŠ€λ§΅μ΄ .js 파일과 같이 있으면 λΈŒλΌμš°μ €μ—μ„œ λ””λ²„κ±°μ—μ„œ μƒˆλ‘œμš΄ index.ts 파일이 λ‚˜νƒ€λ‚œλ‹€. 이제 μ›ν•˜λŠ” λŒ€λ‘œ 브레이크포인트λ₯Ό μ„€μ •ν•  수 있고 λ³€μˆ˜λ₯Ό 쑰사할 수 μžˆλ‹€.

μ†ŒμŠ€λ§΅μ— 원본 μ½”λ“œκ°€ κ·ΈλŒ€λ‘œ ν¬ν•¨λ˜λ„λ‘ μ„€μ •λ˜μ–΄ μžˆμ„ μˆ˜λ„ μžˆλ‹€. κ³΅κ°œλ˜μ§€ μ•Šλ„λ‘ 섀정을 ν™•μΈν•˜λ„λ‘ ν•˜μž.

μ†ŒμŠ€λ§΅μ€ λ‹€μŒκ³Ό 같은 사항듀이 μžˆλ‹€.

  • νƒ€μž…μŠ€ν¬λ¦½νŠΈμ™€ ν•¨κ»˜ λ²ˆλ“€λŸ¬λ‚˜ μ••μΆ•κΈ°λ₯Ό μ‚¬μš©ν•˜κ³  μžˆλ‹€λ©΄, λ²ˆλ“€λŸ¬λ‚˜ μ••μΆ•κΈ°κ°€ 각자의 μ†ŒμŠ€λ§΅μ„ μƒμ„±ν•˜κ²Œ λœλ‹€. 이상적인 디버깅 ν™˜κ²½μ΄ 되렀면 μƒμ„±λœ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ μ•„λ‹Œ 원본 νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ†ŒμŠ€λ‘œ λ§€ν•‘λ˜λ„λ‘ ν•΄μ•Όν•œλ‹€. λ²ˆλ“€λŸ¬κ°€ 기본적으둜 νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ§€μ›ν•œλ‹€λ©΄ 별도 섀정없이 잘 λ™μž‘ν•΄μ•Όν•œλ‹€. κ·Έλ ‡μ§€ μ•Šλ‹€λ©΄ λ²ˆλ“€λŸ¬κ°€ μ†ŒμŠ€λ§΅μ„ 인식할 수 μžˆλ„λ‘ 좔가적인 섀정이 ν•„μš”ν•˜λ‹€.
  • μƒμš© ν™˜κ²½μ— μ†ŒμŠ€λ§΅μ΄ 유좜되고 μžˆλŠ”μ§€ ν™•μΈν•΄μ•Όν•œλ‹€. 디버거λ₯Ό μ—΄μ§€ μ•ŠλŠ” 이상은 μ†ŒμŠ€λ§΅μ΄ λ‘œλ“œλ˜μ§€ μ•ŠμœΌλ―€λ‘œ μ‹€μ œ μ‚¬μš©μžμ—κ²ŒλŠ” μ„±λŠ₯ μ €ν•˜λŠ” λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€. κ·ΈλŸ¬λ‚˜ μ†ŒμŠ€λ§΅μ— 원본 μ½”λ“œμ˜ 인라인 볡사본이 ν¬ν•¨λ˜μ–΄μžˆλ‹€λ©΄ κ³΅κ°œν•΄μ„œλŠ” μ•ˆλ  λ‚΄μš©μ΄ λ“€μ–΄μžˆμ„ 수 μžˆλ‹€. μ €μ§ˆ μ£Όμ„μ΄λ‚˜ λ‚΄λΆ€ 버그 좔적을 μœ„ν•œ URL을 κ³΅κ°œν•  ν•„μš”κ°€ μ—†λ‹€.

NodeJS ν”„λ‘œκ·Έλž¨μ˜ 디버깅에도 μ†ŒμŠ€λ§΅μ„ μ‚¬μš©ν•  수 μžˆλ‹€. 보톡 νŽΈμ§‘κΈ°κ°€ μžλ™ μΈμ‹ν•˜κ±°λ‚˜ NodeJS ν”„λ‘œμ„ΈμŠ€λ₯Ό λΈŒλΌμš°μ € 디버거와 μ—°κ²°ν•˜λ©΄ λœλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ NodeJSλ¬Έμ„œλ₯Ό μ°Έκ³ ν•˜λ„λ‘ν•˜μž.

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