2024-06-03.md

🏑

DIL: μ΄νŽ™ν‹°λΈŒ νƒ€μž…μŠ€ν¬λ¦½νŠΈ

μŠ€ν„°λ””: μ›”κ°„ CS, https://github.com/monthly-cs/2024-05-effective-typescript
μž‘μ„±μΌ: 2024-06-03
μž‘μ„±μž: dusunax


5μž₯: any 닀루기 Use the Narrowest Possible Scope for any Types

  • νƒ€μž… μ‹œμŠ€ν…œ 선택적 (option) 이고 점진적 (gradual) 이기 λ•Œλ¬Έμ— μ •μ μ΄λ©΄μ„œλ„ 동적인 νŠΉμ„±μ„ 가짐 λ™μ‹œμ— 가진닀.

선택적 νƒ€μž… μ‹œμŠ€ν…œ (Optional Typing)

  • ν”„λ‘œκ·Έλž¨μ˜ μΌλΆ€μ—λ§Œ νƒ€μž… μ‹œμŠ€ν…œμ„ μ μš©ν•  수 μžˆλ‹€ -> 점진적 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜
    • νƒ€μž… 체크λ₯Ό λΉ„ν™œμ„±ν™”μ‹œμΌœμ£ΌλŠ” any νƒ€μž…

점진적 νƒ€μž… μ‹œμŠ€ν…œ (Gradual Typing)

  • μ‹œμŠ€ν…œμ΄ λΆ€λΆ„μ μœΌλ‘œ νƒ€μž…μ„ κ²€μ¦ν•˜λŠ” 방식. μ½”λ“œμ˜ μΌλΆ€λŠ” λ™μ μœΌλ‘œ, λ‹€λ₯Έ μΌλΆ€λŠ” μ •μ μœΌλ‘œ νƒ€μž… 검사λ₯Ό μˆ˜ν–‰ν•  수 있ek.
  • ν•„μš”μ— 따라 μ μ§„μ μœΌλ‘œ νƒ€μž…μ„ μΆ”κ°€ν•  수 μžˆλ‹€. μ΄ˆκΈ°μ—λŠ” 동적 νƒ€μž…μœΌλ‘œ μ‹œμž‘ν•˜κ³ , 점차 정적 νƒ€μž…μ„ μΆ”κ°€ν•˜μ—¬ νƒ€μž… μ•ˆμ •μ„±μ„ 높일 수 μžˆλ‹€.

동적 νŠΉμ„± vs 정적 νŠΉμ„±

  • 동적 νŠΉμ„±
    • 동적 타이핑: νƒ€μž…μ„ λͺ…μ‹œν•˜μ§€ μ•Šμ€ λ³€μˆ˜λ‚˜ ν•¨μˆ˜λŠ” λ™μ μœΌλ‘œ νƒ€μž…μ΄ κ²°μ •λœλ‹€. 즉, λŸ°νƒ€μž„ μ‹œμ— λ³€μˆ˜μ˜ νƒ€μž…μ΄ κ²°μ •λ˜λ©°, λ‹€μ–‘ν•œ νƒ€μž…μ˜ 값을 κ°€μ§ˆ 수 μžˆλ‹€.
    • νƒ€μž…μ„ λͺ…μ‹œν•˜μ§€ μ•Šμ€ 뢀뢄은 λŸ°νƒ€μž„μ— λ™μ μœΌλ‘œ νƒ€μž…μ„ κ²°μ •
    • 동적 νƒ€μž… μ–Έμ–΄μ˜ μž₯점인 κ°„κ²°ν•œ 문법과 λΉ λ₯Έ 개발 사이클을 μœ μ§€. μœ μ—°ν•¨!
  • 정적 νŠΉμ„±
    • 정적 타이핑: νƒ€μž…μ„ λͺ…μ‹œν•œ λ³€μˆ˜λ‚˜ ν•¨μˆ˜λŠ” μ •μ μœΌλ‘œ νƒ€μž…μ΄ κ²°μ •λœλ‹€. 즉, 컴파일 μ‹œμ— νƒ€μž…μ΄ κ³ μ •λ˜λ©°, ν•΄λ‹Ή νƒ€μž…μ˜ κ°’λ§Œμ„ κ°€μ§ˆ 수 μžˆλ‹€.
    • 컴파일 νƒ€μž„μ— νƒ€μž… 였λ₯˜λ₯Ό λ°œκ²¬ν•˜κ³  μˆ˜μ •
    • νƒ€μž…μ„ λͺ…μ‹œν•¨μœΌλ‘œμ¨, IDEμ—μ„œμ˜ μžλ™ μ™„μ„±, μ½”λ“œ λ¦¬νŒ©ν† λ§, νƒ€μž… μ•ˆμ „μ„± λ“±μ˜ ν˜œνƒ

μ•„μ΄ν…œ 38: any νƒ€μž…μ€ κ°€λŠ₯ν•œ ν•œ 쒁은 λ²”μœ„μ—μ„œλ§Œ μ‚¬μš©ν•˜κΈ° Use the Narrowest Possible Scope for any Types

ν•¨μˆ˜μ™€ any

  • λ§€κ°œλ³€μˆ˜μ—λ§Œ μ‚¬μš©ν•˜κΈ°
  • ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ€? anyκ°€ λ°˜ν™˜λ˜μ–΄ ν•¨μˆ˜ λ°”κΉ₯에 영ν–₯을 λ―ΈμΉ˜λŠ” 것을 λ°©μ§€ν•˜κΈ° μœ„ν•΄ λ°˜ν™˜ νƒ€μž…μ„ λͺ…μ‹œν•˜λŠ” 것이 μ’‹λ‹€.
function f1() {
  const x: any = expressionReturningFoo(); // ❌ 🀧
  processBar(x);
}
function f2() {
  const x = expressionReturningFoo(); // better.
  processBar(x as any);
  // ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ—λ§Œ μ‚¬μš©λœ ν‘œν˜„μ‹μ΄λ―€λ‘œ λ‹€λ₯Έ μ½”λ“œμ—λŠ” 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠκΈ° λ–„λ¬Έ
  // @ts-ignore, @ts-expect-errorλ₯Ό μ‚¬μš©ν•΄μ„œ anyλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  였λ₯˜ μ œκ±°λ„ κ°€λŠ₯. (λŸ°νƒ€μž„ 였λ₯˜ κ°€λŠ₯μ„±)
}

객체 속성과 any

const config: Config = {
  a: 1,
  b: 2,
  c: {
    key: value,
  },
} as any; // ❌

const config: Config = {
  a: 1,
  b: 2, // λ‹€λ₯Έ 속성은 νƒ€μž… 체크
  c: {
    key: value as any, // ν•„μš”ν•œ μ†μ„±μ˜ κ°’λ§Œ any
  },
};

Things to Remember

  • Make your uses of any as narrowly scoped as possible to avoid undesired loss of type safety elsewhere in your code.
    • μ˜λ„μΉ˜ μ•Šμ€ νƒ€μž… μ•ˆμ •μ„±μ˜ 손싀을 ν”Όν•˜κΈ° μœ„ν•΄μ„œ, anyλ₯Ό μ΅œλŒ€ν•œ 쒁게 μ‚¬μš©ν•  것
  • Never return an any type from a function. This will silently lead to the loss of type safety for code that calls the function.
    • 당신이 anyλ₯Ό λ°˜ν™˜ν•œλ‹€λ©΄... ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ κ³³μ—μ„œ νƒ€μž… μ•ˆμ •μ„±μ„ 아무도 λͺ¨λ₯΄κ²Œ 쑰용히 μžƒκ²Œ λœλ‹€....πŸ’€
  • Use as any on individual properties of a larger object instead of the whole object.
    • 전체 객체 anyλ₯Ό μ‚¬μš©ν•˜μ§€ 말고, κ°œλ³„ 속성에 μ μš©ν•  것

μ•„μ΄ν…œ 39: anyλ₯Ό ꡬ체적으둜 λ³€ν˜•ν•΄μ„œ μ‚¬μš©ν•˜κΈ° Prefer More Precise Variants of any to Plain any

  • anyλŠ”? μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν‘œν˜„ν•  수 μžˆλŠ” λͺ¨λ“  κ°’μ˜ λ²”μœ„
    • 숫자, λ¬Έμžμ—΄, λ°°μ—΄, 객체, μ •κ·œμ‹, ν•¨μˆ˜, 클래슀, DOM μ—˜λ¦¬λ¨ΌνŠΈ, null, undefined
    • anyλ³΄λ‹€λŠ” 더 ꡬ체적으둜 ν‘œν˜„ν•  수 μžˆλŠ” νƒ€μž…μ΄ μžˆλ‹€!

μ˜ˆμ‹œ: any λ³΄λ‹€λŠ” any[]

  • ν•¨μˆ˜ λ‚΄μ˜ array.length νƒ€μž… 체크
  • ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ΄ any λŒ€μ‹  number
  • ν•¨μˆ˜κ°€ 호좜될 λ•Œ, λ§€κ°œλ³€μˆ˜κ°€ 배열인지 체크
function getLengthBad(array: any) {
  // ❌
  return array.length;
}
getLengthBad(/123/);
getLengthBad(null);

function getLength(array: any[]) {
  return array.length; // This is better !
}
getLength(/123/); // 였λ₯˜
//        ~~~~~
// Argument of type 'RegExp' is not assignable to parameter of type 'any[]'.
getLength(null); // 였λ₯˜
//        ~~~~
// Argument of type 'null' is not assignable to parameter of type 'any[]'.
  • 이쀑배열은? any[][]
  • 값을 μ•Œ 수 μ—†λŠ” 객체닀?
    • {[key: string]: any} && Record<string, any>
      • ꡬ체적인 킀와 κ°’μ˜ νƒ€μž…μ„ λ™μ μœΌλ‘œ μ •μ˜
    • object
      • λΉ„κΈ°λ³Έν˜• non-primitive νƒ€μž…μ„ ν¬ν•¨ν•˜λŠ” object νƒ€μž…, ν‚€λ₯Ό μ—΄κ±°ν•  수 μžˆμ§€λ§Œ, 속성에 μ ‘κ·Όν•  수 μ—†λ‹€
      • 객체의 κ΅¬μ‘°λ‚˜ ν”„λ‘œνΌν‹°μ— λŒ€ν•΄ νƒ€μž… 검사λ₯Ό ν•  수 μ—†λ‹€.
        • μ™œλƒ? ꡬ체적인 ν‚€-κ°’ μŒμ„ λ‚˜νƒ€λ‚΄μ§€ μ•ŠκΈ° λ•Œλ¬Έ
  • κ°μ²΄μ΄μ§€λ§Œ 속성에 μ ‘κ·Όν•  수 μ—†μ–΄μ•Ό ν•œλ‹€λ©΄? unknown => 이후 μ•„μ΄ν…œ 42에 두λ‘₯λ‘₯μž₯ μ˜ˆμ •
function hasAKeyThatEndsWithZ(o: Record<string, any>) {
  for (const key in o) {
    if (key.endsWith("z")) {
      console.log(key, o[key]); // keyλ₯Ό 톡해 속성에 μ ‘κ·Ό
      return true;
    }
  }
  return false;
}

function hasAKeyThatEndsWithZ(o: object) {
  for (const key in o) {
    if (key.endsWith("z")) {
      console.log(key, o[key]);
      //               ~~~~~~ Element implicitly has an 'any' type
      //                      because type '{}' has no index signature
      // {} ν˜•μ‹μ— 인덱슀 μ‹œκ·Έλ‹ˆμ²˜κ°€ μ—†μœΌλ―€λ‘œ μš”μ†Œμ— μ•”μ‹œμ μΈ anyκ°€ 있음
      return true;
    }
  }
  return false;
}

ν•¨μˆ˜μ˜ νƒ€μž…κ³Ό any

type Fn0 = () => any; // λ§€κ°œλ³€μˆ˜ 없이 호좜 κ°€λŠ₯ν•œ λͺ¨λ“  ν•¨μˆ˜
type Fn1 = (arg: any) => any; // λ§€κ°œλ³€μˆ˜ 1개
type FnN = (...args: any[]) => any; // λͺ¨λ“  개수의 λ§€κ°œλ³€μˆ˜ === Function
// argsκ°€ λ°°μ—΄ ν˜•νƒœμž„μ„ μ•Œ 수 μžˆλ‹€.
const numArgsBad = (...args: any) => args.length; // anyλ₯Ό λ°˜ν™˜ν•œλ‹€
const numArgsGood = (...args: any[]) => args.length; // nubmerλ₯Ό λ°˜ν™˜ν•œλ‹€

Things to Remember

  • When you use any, think about whether any JavaScript value is truly permissible.
    • anyλ₯Ό μ‚¬μš©ν•  λ•Œ, λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ 값이 μ •λ§λ‘œ ν—ˆμš©λ˜μ–΄μ•Ό ν•˜λŠ” 지 μƒκ°ν•˜κΈ°
  • Prefer more precise forms of any such as any[] or {[id: string]: any} or () => any if they more accurately model your data.
    • κ·Έλƒ₯ any보닀 μ •λ°€ν•œ ν˜•νƒœλ₯Ό λͺ¨λΈλ§ν•˜κΈ°.
    • anyλ₯Ό μ‚¬μš©ν•œ ꡬ체적인 ν˜•νƒœ: any[], any[][], {[id: string]: any}, Record<string, any>, () => any

μ•„μ΄ν…œ 40: ν•¨μˆ˜ μ•ˆμœΌλ‘œ νƒ€μž… 단언문 감좔기 Hide Unsafe Type Assertions in Well-Typed Functions

  • μ™ΈλΆ€ νƒ€μž… μ •μ˜λŠ” κ°„λ‹¨ν•˜μ§€λ§Œ, ν•¨μˆ˜ λ‚΄λΆ€ 둜직이 λ³΅μž‘ν•œ 경우!
    • 내뢀에 νƒ€μž… 단언을 μ‚¬μš©ν•˜κ³ , μ™ΈλΆ€λ‘œ λ“œλŸ¬λ‚˜λŠ” νƒ€μž… μ •μ˜λ₯Ό μ •ν™•νžˆ λͺ…μ‹œ
    • ν”„λ‘œμ νŠΈμ— νƒ€μž… 단언문이 λ“œλŸ¬λ‚˜ μžˆμ§€ μ•Šλ„λ‘ 감좔기

내일 μ΄μ–΄μ„œ 계속.....