2024-05-16.md

🏑

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

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


μ•„μ΄ν…œ 8: νƒ€μž… 곡간과 κ°’ κ³΅κ°„μ˜ μ‹¬λ²Œ κ΅¬λΆ„ν•˜κΈ° Know How to Tell Whether a Symbol Is in the Type Space or Value Space

  • symbol은 νƒ€μž… 곡간(type space)μ΄λ‚˜ κ°’ 곡간(value space) 쀑 ν•œ 곳에 μœ„μΉ˜
    • 이름이 같더라도, μ†ν•˜λŠ” 곡간에 따라 λ‹€λ₯Έ 것을 λ‚˜νƒ€λ‚Ό 수 μžˆλ‹€

νƒ€μž… 곡간과 κ°’ κ³΅κ°„μ˜ μ‹¬λ²Œ

interface Cylinder {
  radius: number;
  height: number;
} // CylinderλŠ” νƒ€μž…. Type space

const Cylinder = (radius: number, height: number) => ({ radius, height }); // CylinderλŠ” ν•¨μˆ˜. Value space

// 였λ₯˜ 상황
function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    shape.radius;
    //    ~~~~~~ Property 'radius' does not exist on type '{}'
    // λŸ°νƒ€μž„μ— Cylinder 심볼을 κ°’μœΌλ‘œ μ—°μ‚°ν•˜λ € ν–ˆμœΌλ―€λ‘œ, κ°’ κ³΅κ°„μ˜ ν•¨μˆ˜ Cylinderλ₯Ό μ°Έμ‘°ν•œλ‹€
  }
}
  • symbol이 value인지 typeμΈμ§€λŠ” λ¬Έλ§₯을 μ‚΄νŽ΄ μ•Œμ•„λ‚΄μ•Ό ν•œλ‹€
  • typescript playgroundλ₯Ό ν™œμš©ν•˜λ©΄μ„œ 컴파일된 μžλ°”μŠ€ν¬λ¦½νŠΈ 결과물을 ν•¨κ»˜ λ³΄λ©΄μ„œ type space & value space κ°œλ… 작기
    • type, interfaceλŠ” type
    • const, let, varλŠ” value
    • μžλ°”μŠ€ν¬λ¦½νŠΈ 컴파일 ν›„ 제거되면 type 정보
    • μžλ°”μŠ€ν¬λ¦½νŠΈ 컴파일 ν›„ λ‚¨μœΌλ©΄ value 정보
    • νƒ€μž… μ„ μ–Έ λ˜λŠ” 단언문 λ‹€μŒμ— λ‚˜μ˜€λŠ” μ‹¬λ²Œμ€ type
    • = λ‹€μŒμ— λ‚˜μ˜€λŠ” μ‹¬λ²Œμ€ value
    • class와 enum은 상황에 따라 type λ˜λŠ” value
interface Person {
  first: string;
  last: string;
}
const jane: Person = { first: "Jane", last: "Jacobs" };
//    ――――           ――――――――――――――――――――――――――――――――― Values
//          ―――――― Type

function email(to: Person, subject: string, body: string): Response {
  //     ――――― ――          ―――――――          ――――                    Values
  //               ――――――           ――――――        ――――――   ―――――――― Types
  // ...
}

class, enum

  • ν΄λž˜μŠ€κ°€ νƒ€μž…μœΌλ‘œ 쓰일 λ•ŒλŠ”: ν˜•νƒœ(속성과 λ©”μ„œλ“œ)κ°€ μ‚¬μš©λ¨
  • ν΄λž˜μŠ€κ°€ κ°’μœΌλ‘œ 쓰일 λ•ŒλŠ” μƒμ„±μžκ°€ μ‚¬μš©λ¨
class Cylinder {
  radius: number;
  height: number;
  constructor(radius: number, height: number) {
    this.radius = radius;
    this.height = height;
  }
}

function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    // Cylinderλ₯Ό κ°’μœΌλ‘œ μ—°μ‚°
    // μƒμ„±μžκ°€ μ‚¬μš©λ¨
    shape;
    // ^? (parameter) shape: Cylinder, νƒ€μž…μœΌλ‘œ μ°Έμ‘°
    // ν˜•νƒœ(속성과 λ©”μ„œλ“œ)κ°€ μ‚¬μš©λ¨
    shape.radius;
    //    ^? (property) Cylinder.radius: number, νƒ€μž…μœΌλ‘œ μ°Έμ‘°
  }
}
  • typeofλŠ” 값을 μ½μ–΄μ„œ, νƒ€μž…μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€
    • type space(νƒ€μž… 곡간)의 typeofλŠ” subset으둜 μ‚¬μš©ν•  수 있고, type ꡬ문으둜 이름을 λΆ™μ΄λŠ” μš©λ„λ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.
    • value spaceμ—μ„œ, typeofλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ λŸ°νƒ€μž„μ˜ typeof이 λœλ‹€.
      • 6개의 λŸ°νƒ€μž„ νƒ€μž…λ§Œ μ‘΄μž¬ν•΄μ™”λ‹€. (string, number, boolean, undefined, object, function)
interface Person {
  first: string;
  last: string;
}
const jane: Person = { first: "Jane", last: "Jacobs" };
const email = (to: Person, subject: string, body: string) => {};

type T1 = typeof jane;
//   ^? type T1 = Person
type T2 = typeof email;
//   ^? type T2 = (to: Person, subject: string, body: string) => Response

const v1 = typeof jane; // Value is "object"
const v2 = typeof email; // Value is "function"

console.log(v1, v2); // "object",  "function"

ν΄λž˜μŠ€μ™€ νƒ€μž…

class Cylinder {
  radius: number;
  height: number;
  constructor(radius: number, height: number) {
    this.radius = radius;
    this.height = height;
  }
}

const v = typeof Cylinder; // Value is "function"
// ν΄λž˜μŠ€κ°€ μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” ν•¨μˆ˜λ‘œ κ΅¬ν˜„λ˜κΈ° λ•Œλ¬Έμ—, vλŠ” function이닀.
type T = typeof Cylinder; // Type is typeof Cylinder
// T의 CylinderλŠ” μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ΄ μ•„λ‹ˆλΌ, μƒμ„±μž ν•¨μˆ˜μ΄λ‹€.
// Tλ₯Ό value spaceμ—μ„œλŠ” 확인할 수 μ—†μŒ. (νƒ€μž…μ΄κΈ° λ•Œλ¬Έ)

console.log(v); // "function"
  • 예제의 μ½”λ“œ(그런데? νƒ€μž…λ§Œ μ„ μ–Έν•˜λ©΄ λŸ°νƒ€μž„ 였λ₯˜: fn is not defined)
    • declare
      • declareλŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ λ³€μˆ˜, ν•¨μˆ˜, 클래슀 등이 이미 λ‹€λ₯Έ κ³³μ—μ„œ μ •μ˜λ˜μ–΄ μžˆλ‹€κ³  μ„ μ–Έν•˜λŠ” ν‚€μ›Œλ“œ
      • μ»΄νŒŒμΌλŸ¬μ—κ²Œ ν•΄λ‹Ή μ‹λ³„μžμ— λŒ€ν•œ 정보λ₯Ό μ œκ³΅ν•˜κ³  μ‹€μ œ κ΅¬ν˜„μ„ μ œκ³΅ν•˜μ§€ μ•ŠλŠ” 것
    • InstaceType μ œλ„ˆλ¦­μ„ μ‚¬μš©ν•΄ μƒμ„±μž νƒ€μž…κ³Ό μΈμŠ€ν„΄μŠ€ νƒ€μž…μ„ μ „ν™˜
declare let fnA: T; // νƒ€μž…μ΄ μƒμ„±μž typeof Cylinderμž„μ„ 확인 κ°€λŠ₯(fn is not defined)
let fnB: T = Cylinder; // μ„ μ–Έκ³Ό ν•¨κ»˜ 값을 ν• λ‹Ήν•΄μ£Όλ©΄ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•  수 있음
type fnC = InstanceType<typeof Cylinder>; // νƒ€μž…μ΄ μƒμ„±μž typeof Cylinderμž„μ„ 확인 κ°€λŠ₯(fn is not defined)

const c = new fnB(10, 5);
console.log(v, c);