TS study: νƒ€μž…μ‹œμŠ€ν…œ (1)

@choi2021 Β· January 07, 2023 Β· 16 min read

🎚 νƒ€μž…μ‹œμŠ€ν…œ

νƒ€μž… μ‹œμŠ€ν…œμ€ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•˜λŠ” 큰 이유 쀑 ν•˜λ‚˜λ‹€. νƒ€μž…μ„ 톡해 μ•ˆμ „ν•˜κ³  효율적으둜 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 있게 도와주기 λ•Œλ¬Έμ— νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μž˜ν•œλ‹€λŠ” κ²ƒμ˜ μ˜λ―Έκ°€ ν˜„μž¬ μ–Όλ§ˆλ‚˜ νƒ€μž…μ„ 잘 μ •μ˜ν•˜λƒμ— μžˆλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μ΅œλŒ€ν•œ ꡬ체적으둜 νƒ€μž…μ„ μž˜μ •μ˜ν•˜κΈ° μœ„ν•΄ νƒ€μž…μ‹œμŠ€ν…œμ— λŒ€ν•΄ μ•Œμ•„λ³΄μž

πŸ€” νƒ€μž… μΆ”λ‘ 

νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” λ˜‘λ˜‘ν•˜κΈ° λ•Œλ¬Έμ— μš°λ¦¬κ°€ μž‘μ„±ν•œ μ½”λ“œμ— λͺ…μ‹œμ μœΌλ‘œ μ „λ‹¬ν•˜μ§€ μ•Šμ•„λ„ μ½”λ“œμ˜ 흐름을 톡해 μΆ”λ‘ ν•΄μ€€λ‹€. const s="string"μ΄λΌλŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ μžλ™μœΌλ‘œ sμ—λŠ” stringνƒ€μž…μ΄ ν• λ‹Ήλœλ‹€.

const foo = {
  x: [1, 2, 3], // number[]
  bar: {
    name: "fred",
  },
}

μœ„ 예제의 xλŠ” [1,2,3]을 보고 number[]을 νƒ€μž…μœΌλ‘œ μΆ”λ‘ ν–ˆλ‹€. ν•˜μ§€λ§Œ λ§Œμ•½μ— λ°°μ—΄μ˜ 길이가 μ •ν•΄μ Έ μžˆλŠ” Tupleμ΄μ—ˆλ‹€λ©΄ μœ„μ˜ νƒ€μž…μ€ 이후에 μ—λŸ¬λ₯Ό λ§Œλ“€ 수 μžˆλŠ” μ½”λ“œκ°€ λœλ‹€.

κ·Έλž˜μ„œ μ΅œλŒ€ν•œ ꡬ체적으둜 νƒ€μž…μ„ μ •ν•΄μ£ΌλŠ” 것이 μ€‘μš”ν•˜λ©° λŒ€λΆ€λΆ„μ˜ λΌμ΄λΈŒλŸ¬λ¦¬μ—λŠ” μ‚¬μš©ν•˜λŠ” 속성과 λ©”μ†Œλ“œμ— λŒ€ν•œ 정보듀이 d.ts둜 λλ‚˜λŠ” νŒŒμΌμ— μ •λ¦¬λ˜μ–΄ 있기 λ•Œλ¬Έμ— μ°Έκ³ ν•  수 μžˆλ‹€.

[lib.es2015.core.d.ts의 Array interface]

d.ts
d.ts

πŸ—‚νƒ€μž…κ³Ό μ§‘ν•©μ˜ 관계

μ•„λž˜ 그림을 톡해 μ—„μ²­λ‚˜κ²Œ λ‹€μ–‘ν•œ νƒ€μž…μ΄ μ‘΄μž¬ν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€. μ΄λŸ¬ν•œ νƒ€μž…μ‹œμŠ€ν…œμ„ μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œ νƒ€μž…μ„ μ§‘ν•©μœΌλ‘œ 이해해야 ν•œλ‹€.

img

νƒ€μž…κ³Ό μ§‘ν•©μ΄λΌλ‹ˆ... 관련이 μ—†μ–΄ λ³΄μ΄μ§€λ§Œ, μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν”„λ‘œν† νƒ€μž…μ˜ λΆ€λͺ¨ μžμ‹ 관계가 μžˆλ“―μ΄, νƒ€μž…λ“€μ—λ„ μ§‘ν•© 관계가 μžˆλ‹€. unknown type은 μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ— μ–΄λ–€ 것이든 λ‹€ 될 수 μžˆλŠ” κ°€μž₯ 큰 μ§‘ν•©μœΌλ‘œ neverλŠ” μ–΄λ–€ μš”μ†Œλ„ ν¬ν•¨ν•˜μ§€ μ•ŠλŠ” κ°€μž₯ μž‘μ€ μ§‘ν•©μœΌλ‘œ 이해할 수 μžˆλ‹€.

const x: never = 12 //Type 'number' is not assignable to type 'never'.

unit type

ν•˜λ‚˜μ˜ 값을 κ°€λ¦¬ν‚€λŠ” νƒ€μž…μ€ unit type λ˜λŠ” literal type이라고 λΆˆλ¦¬λŠ” νƒ€μž…μ΄λ‹€. 값을 직접 type에 λͺ…μ‹œν•œλ‹€.

type A = "A"

Union Type

ν•˜λ‚˜κ°€ μ•„λ‹ˆλΌ νƒ€μž…μ— μ—¬λŸ¬ 값을 ν•¨κ»˜ λ‚˜νƒ€λ‚΄κΈ° μœ„ν•΄μ„œ union type이 μ‘΄μž¬ν•œλ‹€. union type은 μ—¬λŸ¬ 개의 νƒ€μž…μ„ ν•©ν•œ ν•©μ§‘ν•©μœΌλ‘œ |으둜 λ‚˜νƒ€λ‚Έλ‹€.

κ·Έλ¦Ό 5-7 A와 B의 ν•©μ§‘ν•©

type AB = "A" | "B"
const ab: AB = Math.random() < 0.5 ? "A" : "B"
const c: AB = "C" // Type '"C"' is not assignable to type 'AB'

μœ„ μ˜ˆμ œμ—μ„œ abλŠ” AB μœ λ‹ˆμ˜¨ νƒ€μž…μœΌλ‘œ λ˜μ–΄ μžˆμ–΄ "A"λ‚˜ "B"κ°€ 할당될 수 μžˆλ‹€. cλŠ” ABνƒ€μž…μ— μ •μ˜ν•œ "A" λ˜λŠ” "B"의 뢀뢄집합이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. 즉 νƒ€μž… 체크λ₯Ό ν•œλ‹€λŠ” 것은 μ–΄λ–€ 집합이 λ‹€λ₯Έ μ§‘ν•©μ˜ 뢀뢄집합이 될 수 μžˆλŠ”μ§€ λ₯Ό ν™•μΈν•˜λŠ” 것이닀.

Intersection Type

μ—¬λŸ¬ 개 νƒ€μž…μ„ λ™μ‹œμ— λ§Œμ‘±ν•˜λŠ” λΆ€λΆ„ μ§‘ν•©, ꡐ집합을 Intersection Type이라고 ν•˜λ©° &으둜 λ‚˜νƒ€λ‚Έλ‹€.

κ·Έλ¦Ό 5-8 A와 B의 ꡐ집합

μ—¬κΈ°μ„œ μ΄ν•΄ν•˜κΈ° μ–΄λ €μ› λ˜ 뢀뢄이 "λ‘˜ λ‹€ λ§Œμ‘±ν•œλ‹€"고만 생각해 Union type와 차이가 μ΄ν•΄λ˜μ§€ μ•Šμ•˜μ§€λ§Œ μ§‘ν•©μœΌλ‘œ μƒκ°ν•΄λ³΄λ‹ˆ 이해가 쉬웠닀. λ™μ‹œμ— λ§Œμ‘±ν•œλ‹€λŠ” 것은 두 μ§‘ν•©μ˜ 쑰건을 λͺ¨λ‘ λ§Œμ‘±ν•œλ‹€λŠ” 의미λ₯Ό κ°€μ§„λ‹€.

interface dogPerson {
  loveDog: true
}

interface catPerson {
  loveCat: true
}

type Both = dogPerson & catPerson
const person1: Both = {
  loveDog: true,
  loveCat: true,
}

μœ„ μ˜ˆμ œμ—μ„œ 강아지와 고양이λ₯Ό λͺ¨λ‘ μ’‹μ•„ν•˜λŠ” person1은 loveDogκ³Ό loveCat을 λͺ¨λ‘ true둜 κ°€μ§€κ³  μžˆμ–΄μ•Ό ν•œλ‹€. λ‘˜ λ‹€ λ§Œμ‘±ν•œλ‹€λŠ” 것은 두 κ°€μ§€ type을 λͺ¨λ‘ λ§Œμ‘±ν•΄μ•Ό ν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

μ§‘ν•© 관계λ₯Ό λ‹€μ–‘ν•œ 예제λ₯Ό 톡해 μ’€ 더 μ•Œμ•„λ³΄μž.

keyof와 ν•¨κ»˜ μ‚¬μš©ν•˜λŠ” union typeκ³Ό intersection type

interface dogPerson {
  loveDog: true;
}

interface catPerson {
  loveCat: true;
}

interface Both = dogPerson & catPerson;

type K = keyof (dogPerson | catPerson); //  (keyof A) & (keyof B)
type T= keyof(dogPerson & catPerson) //  (keyof A) | (keyof B)

const a: K = "loveDog"; // Type 'string' is not assignable to type 'never'.
const b: T = 'loveDog';

KλŠ” ν•©μ§‘ν•©μ˜ key둜 ꡐ집합인 never type이 되고, TλŠ” κ΅μ§‘ν•©μ˜ key이기 λ•Œλ¬Έμ— A의 key와 B의 key의 "loveDog"|'loveDog'κ°€ λœλ‹€. 이뢀뢄은 아직 와닿지 μ•Šμ•„μ„œ κ³„μ†ν•΄μ„œ 곡뢀가 ν•„μš”ν•œ 뢀뢄인 것 κ°™λ‹€.

extends

interface dogPerson {
  loveDog: true
}

interface catPerson {
  loveCat: true
}

interface Both extends dogPerson {
  loveCat: true
}

μ•žμ„œ intersection type으둜 μ •μ˜ν–ˆλ˜ 관계λ₯Ό extendsλ₯Ό μ΄μš©ν•΄ 상속 κ΄€κ³„λ‘œλ„ 이해할 수 μžˆλ‹€. λΆ€λͺ¨μ˜ 속성을 μžμ‹μ΄ 전달 λ°›κΈ° λ•Œλ¬Έμ— μžμ‹μ„ subset λΆ€λͺ¨λ₯Ό superset이라고 λΆ€λ₯΄λŠ” μ§‘ν•© 관계와 상속 관계가 μΌμΉ˜ν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

interface Point {
  x: number
  y: number
}

type PointKeys = keyof Point // "x"|"y"

function sortBy<K extends keyof T, T>(vals: T[], key: K): T[] {
  // ..
  return []
}

const pts: Point[] = [{ x: 1, y: 1 }]
sortBy(pts, "x") // T: Point[] K:"x"
sortBy(pts, "y") // T: Point[] K:"y"
sortBy(pts, "z") // T: Point[] K:"z" // Argument of type '"z"' is not assignable to parameter of type 'keyof Point'.

μœ„μ˜ generic을 μ΄μš©ν•œ μ˜ˆμ‹œλ₯Ό 보면 Tμ—λŠ” point[]νƒ€μž…μ΄ Kμ—λŠ” "x", "y", "z"κ°€ λ“€μ–΄κ°„λ‹€. KλŠ” K의 key의 λΆ€λΆ„μ§‘ν•©μ΄μ–΄μ•Όν•˜λ―€λ‘œ "z"λŠ” point의 "x"|"y" 집합에 μ†ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

⁉ κ°’κ³Ό νƒ€μž… κ΅¬λΆ„ν•˜κΈ°

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” κ°’λ§Œ μ‹ κ²½μ¨μ„œ 이름을 μ •ν•˜λ©΄ λμ§€λ§Œ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ type에도 넀이밍이 ν•„μš”ν•΄μ‘Œλ‹€. λ‚΄κ°€ μ •μ˜ν•œ 것이 값인지 νƒ€μž…μΈμ§€λ₯Ό 이해할 ν•„μš”κ°€ μžˆλ‹€.

interface Cylinder {
  radius: number
  height: number
}

const Cylinder = (radius: number, height: number) => ({ radius, height })
// Cannot redeclare block-scoped variable 'Cylinder'.

같은 μ΄λ¦„μœΌλ‘œ νƒ€μž…κ³Ό κ°’ λͺ¨λ‘ μ •μ˜ν•  수 있기 λ•Œλ¬Έμ— ꡬ뢄할 수 μžˆλŠ” 넀이밍이 ν•„μš”ν•˜λ‹€.

interface Cylinder {
  radius: number
  height: number
}

function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    // 'Cylinder' only refers to a type, but is being used as a value here.
    shape.radius
  }
}

넀이밍 문제 뿐 μ•„λ‹ˆλΌ νƒ€μž…μ„ κ°’μ²˜λŸΌ μ‚¬μš©ν•΄ 였λ₯˜λ₯Ό λ§Œλ“€κΈ°λ„ ν•œλ‹€. instanceofλŠ” λŸ°νƒ€μž„ μ—°μ‚°μžλ‘œ 값을 ν™•μΈν•œλ‹€. Cylinderκ°€ νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ‚œ 것을 λ³Ό 수 μžˆλ‹€.

μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλŠ” λ°©λ²•μœΌλ‘œλŠ” κ°’κ³Ό νƒ€μž… λͺ¨λ‘ 될 수 μžˆλŠ” class λ₯Ό μ‚¬μš©ν•΄ ν•΄κ²°ν•  수 μžˆλ‹€.

class Cylinder {
  radius: number
  height: number
}

function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    // 'Cylinder' only refers to a type, but is being used as a value here.
    shape.radius
  }
}

typeof

typeofλŠ” class처럼 νƒ€μž…κ³Ό κ°’μ˜ 의미λ₯Ό λͺ¨λ‘ κ°€μ§„λ‹€. νƒ€μž…μœΌλ‘œ 쓰일 λ•ŒλŠ” ν•΄λ‹Ή κ°’μ˜ νƒ€μž…μ„ 읽고, κ°’μœΌλ‘œ 쓰일 λ•ŒλŠ” ν•΄λ‹Ή κ°’μ˜ νƒ€μž…μ„ λ¬Έμžμ—΄λ‘œ λ°˜ν™˜ν•œλ‹€.

const v = typeof Cylinder
console.log(v) // function

type C = InstanceType<typeof Cylinder> // Cylinder

// type InstanceType<T extends abstract new (...args: any) => any> =
//   T extends abstract new (...args: any) => infer R ? R : any;

μœ„ μ˜ˆμ œμ—μ„œ typeofκ°€ κ°’μœΌλ‘œ μ“°μ—¬ vκ°€ "function"λ¬Έμžμ—΄ κ°’μœΌλ‘œ λ°˜ν™˜λ˜μ—ˆκ³ , νƒ€μž…μœΌλ‘œ 쓰일 경우 Genericκ³Ό ν•¨κ»˜ μ“°μ—¬ C의 νƒ€μž…μ΄ Cylinder둜 λ‚˜μ˜¨ 것을 λ³Ό 수 μžˆμ—ˆλ‹€. 여기에 쓰인 InstanceType은 μœ ν‹Έλ¦¬ν‹° νƒ€μž…μœΌλ‘œ μƒμ„±μž ν•¨μˆ˜ T의 instance type을 μ˜λ―Έν•œλ‹€.

Branket μ ‘κ·Όμž

였브젝트의 속성 μ ‘κ·ΌμžμΈ []λŠ” νƒ€μž…μ—μ„œλ„ λ™μΌν•˜κ²Œ νƒ€μž…μ˜ μ†μ„±μ˜ νƒ€μž…μ •λ³΄λ₯Ό 얻을 수 μžˆλ‹€.

interface Person {
  first: string
  last: string
}

type PersonEl = Person["first" | "last"]
type Person2 = Person.first // Cannot access 'Person.first' because 'Person' is a type, but not a namespace.

type Tuple = [string, number, Date]
type TupleEl = Tuple[number]

ꡬ쑰 λΆ„ν•΄ ν• λ‹Ή

ꡬ쑰 λΆ„ν•΄ ν• λ‹ΉμœΌλ‘œ 자주 μ‚¬μš©ν•˜λŠ” κ²½μš°λŠ” reactμ—μ„œ 전달 받은 propsλ₯Ό ꡬ쑰 ν• λ‹Ή λΆ„ν•΄λ‘œ νƒ€μž…μ„ λͺ…μ‹œν•΄ 쀄 λ•Œμ˜€λ‹€. κΈΈμ–΄μ§ˆ 수 있기 λ•Œλ¬Έμ— type을 λ”°λ‘œ λΉΌμ„œ μ •μ˜ν•˜λŠ” 게 가독성에 μ’‹μ•˜λ‹€.

type AdminDescriptionItemType = {
  item: DescriptionType
  name: DescriptionNameType
  onDelete: (name: DescriptionNameType, id: string) => void
  onChange: (name: DescriptionNameType, value: string, id: string) => void
}

export default function AdminDescriptionItem({
  item,
  name,
  onDelete,
  onChange,
}: AdminDescriptionItemType) {
  // ...μƒλž΅
}

😁 νƒ€μž… 단언 보닀 νƒ€μž…μ„ μ–Έ

νƒ€μž… 단언 (type assertion)은 μΆ”λ‘ ν•œ νƒ€μž…κ³Ό 상관없이 κ°œλ°œμžκ°€ μ •μ˜ν•œ νƒ€μž…μ„ μš°μ„ μˆœμœ„λ‘œ 두기 λ•Œλ¬Έμ— 였λ₯˜κ°€ λ°œμƒν•  ν™•λ₯ μ΄ λ†’μ•„μ§„λ‹€.

interface Person {
  name: string
}

const alice: Person = { name: "Alice" }
const bob = {} as Person

alice의 경우 νƒ€μž… 선언을 μ΄μš©ν•΄ νƒ€μž… μ²΄ν¬ν•˜κΈ° λ•Œλ¬Έμ— λͺ…μ‹œλœ κ°’μ˜ νƒ€μž…μ΄ λ§žλŠ” μ§€λ₯Ό λ³΄μ§€λ§Œ, bob은 λ‚΄κ°€ μ •μ˜ν•œ Person이라고 μ§€μ •ν•˜κ²Œ λ˜μ–΄ 였λ₯˜λ₯Ό λ˜μ§€μ§€ μ•ŠλŠ”λ‹€.

const alice: Person = {
  name: "Alice",
  occupation: "td",
} // Type '{ name: string; occupation: string; }' is not assignable to type 'Person'.

const bob = {
  name: "bob",
  occupation: "js",
} as Person

μ΄λ²ˆμ—λŠ” Personμ—μ„œ μ •μ˜ν•œ 속성 μ™Έμ˜ μΆ”κ°€ 속성이 μžˆμ„ λ•Œλ‘œ alice의 경우 κΈ°μ‘΄ μ •μ˜ν•œ μ†μ„±μ™Έμ˜ λ‹€λ₯Έ 속성이 μžˆμŒμ„ 였λ₯˜λ‘œ μ•Œλ € μ£Όμ§€λ§Œ, bob은 Person으둜 이미 νƒ€μž…μ²΄ν¬λ₯Ό ν–ˆλ‹€κ³  μ „λ‹¬ν•˜λŠ” 것과 κ°™μ•„ 였λ₯˜κ°€ μ—†λŠ” 것을 λ³Ό 수 μžˆλ‹€.

νƒ€μž… μ„ μ–Έ μ‹œ μ£Όμ˜ν•  점

const people = ["alice", "bob", "jan"].map(name => ({ name })) // {name:string}[]

μœ„μ˜ 경우 νƒ€μž…μ΄ Person[]이 되기λ₯Ό κΈ°λŒ€ν–ˆμ§€λ§Œ {name:string}[]둜 type이 μ •ν•΄μ§„λ‹€. μ΄λŸ¬ν•œ κ²½μš°λŠ” 체이닝을 μ΄μ–΄λ‚˜κ°ˆ λ•Œ type μ—λŸ¬λ₯Ό λ§Œλ“€κΈ° λ•Œλ¬Έμ— 항상 μ˜ˆμƒν•˜λŠ” νƒ€μž…κ³Ό κ°™κ²Œ λ§Œλ“€κΈ° μœ„ν•΄ 쀑간 λ‹¨κ³„μ˜ μ˜ˆμΈ‘ν•œ νƒ€μž…μ„ λͺ…μ‹œν•¨μœΌλ‘œμ¨ 였λ₯˜κ°€ λ°œμƒν•œ 곳을 λΉ λ₯΄κ²Œ μ°Ύμ•„λ‚˜κ°ˆ 수 μžˆλ‹€.

const people: Person[] = ["alice", "bob", "jan"].map(
  (name): Person => ({ name })
)

πŸ™„ νƒ€μž… 단언은 μ–Έμ œ μ“ΈκΉŒ?

νƒ€μž… 단언이 ν•„μš”ν•œ κ²½μš°λŠ” λ‚΄κ°€ μ •μ˜ν•˜λŠ” νƒ€μž…μ΄ μΆ”λ‘ ν•˜λŠ” νƒ€μž…λ³΄λ‹€ 더 μ •ν™•ν•  λ•Œλ‹€. λ‹Ήμ—°νžˆ νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ 더 λ˜‘λ˜‘ν•œλ° λ‚΄κ°€ λ§žλ‹€κ³  ν•  수 μžˆμ„κΉŒ 싢기도 ν•˜μ§€λ§Œ λŸ°νƒ€μž„μ—μ„œ κ²°μ •λ˜λŠ” 경우 νƒ€μž… μŠ€ν¬λ¦½νŠΈκ°€ μ ‘κ·Όν•  수 μ—†κ³ , 이미 μ •ν•΄μ Έ μžˆμ§€λ§Œ νƒ€μž…μ΄ λ°˜μ˜λ˜μ–΄μžˆμ§€ μ•Šμ€ κ²½μš°μ—λ„ μ‚¬μš©ν•  수 μžˆμ„ 것 κ°™λ‹€.

document.querySelector("#myButton")?.addEventListener("click", e => {
  e.currentTarget
  const button = e.currentTarget as HTMLButtonElement
  button
})

event의 currentTarget은 λŸ°νƒ€μž„μ—μ„œ κ²°μ •λ˜λ―€λ‘œ null|HTMLButtonElementμ€‘μ—μ„œ HTMLButtonElement둜 μ •ν•΄μ€˜μ•Ό ν•œλ‹€.

졜근 과제λ₯Ό ν•˜λ©΄μ„œ νƒ€μž…λ‹¨μ–Έμ΄ ν•„μš”ν•œ κ²½μš°κ°€ μžˆμ—ˆλ‹€. μ˜μ–΄λ‘œ 였늘의 μš”μΌμ„ 가져와야 ν•  λ•Œ toLocaleDateString()λ₯Ό μ΄μš©ν•΄μ„œ μ‚¬μš©ν•˜λ € ν–ˆμ§€λ§Œ νƒ€μž… μ •μ˜κ°€ string으둜 λ˜μ–΄μžˆμ–΄ νƒ€μž…μ—λŸ¬κ°€ λ°œμƒν–ˆλ‹€.

단언
단언

이점을 ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ 고민을 ν•˜λ‹€κ°€ μ •μ˜ λ˜μ–΄μžˆλŠ” νƒ€μž…λ³΄λ‹€ 더 μžμ„Ένžˆ μ •ν•΄μ€˜μ•Ό ν•˜λŠ” μƒν™©μ΄λ―€λ‘œ νƒ€μž…λ‹¨μ–Έμ„ μ‚¬μš©ν•΄μ„œ ν•΄κ²°ν•  수 μžˆμ—ˆλ‹€.

const today = new Date()
const day = today.toLocaleDateString("en", {
  weekday: "short",
}) as EnKeys

const Days = {
  Mon: "μ›”",
  Tue: "ν™”",
  Wed: "수",
  Thu: "λͺ©",
  Fri: "금",
  Sat: "ν† ",
  Sun: "일",
  Temp: "당일",
} as const

export type EnKeys = keyof typeof Days

νƒ€μž… 단언을 항상 μ‚¬μš©ν•  수 μžˆλŠ” 것은 μ•„λ‹ˆλ‹€. A|B typeμ—μ„œ Aκ°€ B의 λΆ€λΆ„ 집합일 λ•Œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

interface Person {
  name: string
}
const body = document.body
const el = body as Person
// Conversion of type 'HTMLElement' to type 'Person' may be a mistake because neither type sufficiently overlaps with the other. // If this was intentional, convert the expression to 'unknown' first.
const el = body as unkown as Person

Person으둜 νƒ€μž… 단언을 톡해 νƒ€μž…μ„ μ •ν•˜λ € ν–ˆμ§€λ§Œ bodyκ°€ κ°€μ§€λŠ” type인 HTMLElement와 Person은 μ„œλ‘œ 관계가 μ—†κΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. ν•˜μ§€λ§Œ unknown은 κ°€μž₯ 큰 νƒ€μž…μ˜ μ§‘ν•©μ΄λ―€λ‘œ νƒ€μž… 단언이 κ°€λŠ₯ν•œ 것을 λ³Ό 수 μžˆλ‹€.

마치며

νƒ€μž… μ‹œμŠ€ν…œμ„ κ³΅λΆ€ν•˜λ©΄μ„œ νƒ€μž…μ„ μ§‘ν•©μ΄λΌλŠ” μ‹œμ μœΌλ‘œ λ³΄λ‹ˆ μ’€ 더 이해가 잘 λ˜μ—ˆλ‹€. ν•˜μ§€λ§Œ μ—¬μ „νžˆ λΆ€μ‘±ν•œ 점이 λ§Žμ•„μ„œ μ—¬λŸ¬ 번 읽어야 ν•  뢀뢄이라 μƒκ°λœλ‹€.

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

@choi2021
맀일의 μ‹œν–‰μ°©μ˜€λ₯Ό κΈ°λ‘ν•˜λŠ” κ°œλ°œμΌμ§€μž…λ‹ˆλ‹€.