๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Language/TypeScript

[TypeScript] ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์˜ ๊ฐ’์„ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ

 

 

 

 

์ค‘์ฒฉ๋œ ๊ฐ์ฒด์—์„œ ๊ฐ’๋งŒ ๋ฝ‘์•„์„œ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?
๐Ÿค”

 

 

 

 

 

 

const ENDPOINTS = {
  AUTH: {
    SIGN_UP: 'POST /auth/sign-up',
    SIGN_IN: 'POST /auth/sign-in'
  }
}

 

๋งŒ์•ฝ ์ด๋Ÿฐ ํ˜•ํƒœ์˜ ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.

 

์ด ๊ฐ์ฒด์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ENDPOINTS.AUTH.SIGN_UP ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ œ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ ์ด๋ ‡๊ฒŒ ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์—์„œ value๋งŒ ๋ชจ์•„์„œ ํ•˜๋‚˜์˜ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ˆ˜๋™์œผ๋กœ type Endpoint = 'POST /auth/sign-up' | 'POST /auth/sign-in' | ... ๋กœ ์„ ์–ธํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ,

 

์ด ๊ฐ์ฒด์˜ ๋ชธ์ง‘์ด ํ›จ์”ฌ ๋” ํฌ๋‹ค๊ณ  ํ•  ๋•Œ๋Š” ๊ฝค๋‚˜ ๊ท€์ฐฎ๊ณ  ๋”๋Ÿฌ์šด ์ฝ”๋“œ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

 

 

์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

const ENDPOINTS = {
  AUTH: {
    SIGN_UP: "POST /auth/sign-up",
    SIGN_IN: "POST /auth/sign-in"
  }
} as const;

type NestedValues<T> = T extends object ? NestedValues<T[keyof T]> : T;

type Endpoint = NestedValues<typeof ENDPOINTS>;

 

์ฒซ์งธ, NestedValues<T>์—์„œ <T>๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

 

๋‘˜์งธ, T extends object ? a : b ๋Š” TypeScript์˜ ์กฐ๊ฑด๋ถ€ ํƒ€์ž…(conditional types)์œผ๋กœ,

 

extends์˜ ์™ผ์ชฝ ํƒ€์ž…์„ extends์˜ ์˜ค๋ฅธ์ชฝ ํƒ€์ž…์—  ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด a๋ฅผ, ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด b๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

 

T๊ฐ€ ๊ฐ์ฒด๋ผ๋ฉด NestedValues<T[keyof T>, T๊ฐ€ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด T๊ฐ€ ํƒ€์ž…์ด ๋ฉ๋‹ˆ๋‹ค.

 

 

์…‹์งธ, keyof๋Š” ๊ฐ์ฒด ํƒ€์ž… T์˜ key๋งŒ ๋ฝ‘์•„์„œ ์œ ๋‹ˆ์–ธ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ T[keyof T]๋Š” ๊ฐ์ฒด์˜ ๊ฐ’์ด ๋˜๊ฒ ์ง€์š”.

 

๊ฒฐ๊ณผ์ ์œผ๋กœ type NestedValues<T> = T extends object ? NestedValues<T[keyof T]> : T ๋Š”

 

์ค‘์ฒฉ ๊ฐ์ฒด์—์„œ ๊ฐ’๋งŒ ์žฌ๊ท€์ ์œผ๋กœ ์ถ”์ถœํ•˜์—ฌ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“œ๋Š” ์ปค์Šคํ…€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

 

๋„ท์งธ, TypeScript์—์„œ์˜ typeof๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ณ€์ˆ˜๋‚˜ ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

(JS์—์„œ๋Š” ๋Ÿฐํƒ€์ž„์—์„œ string์œผ๋กœ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์šฉ๋„๋กœ๋งŒ ๊ฐ€๋Šฅ)

 

type Endpoints = NestedValues<typeof ENDPOINTS>;

 

์ด ๊ตฌ๋ฌธ์—์„œ๋Š” ENDPOINTS๊ฐ€ ๊ฐ์ฒด์ด๋ฏ€๋กœ ๊ฐ์ฒด์˜ ํƒ€์ž… ๊ตฌ์กฐ๋ฅผ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

typeof ENDPOINTS๋Š” IDE์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ์ถ”๋ก ํ•ด์ค๋‹ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋๋‚ด๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. 

 

typeof ์—ฐ์‚ฐ์ž๋กœ ๊ฐ์ฒด์˜ ์›๋ž˜ ๊ฐ’์˜ ํƒ€์ž…์— ๋”ฐ๋ผ string์œผ๋กœ ์ถ”๋ก ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—

 

NestedValues<typeof ENDPOINTS>์˜ ๊ฒฐ๊ณผ๋Š” string์ด ๋˜์–ด๋ฒ„๋ฆฌ๊ฑฐ๋“ ์š”.

 

 

๋‹ค์„ฏ์งธ, ์›๋ž˜ ๋ชฉํ‘œ์˜€๋˜ ๊ฐ์ฒด์˜ ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์„ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“œ๋ ค๋ฉด ๊ฐ์ฒด ์„ ์–ธ์— as const๋ฅผ ๋ถ™์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋ฅผ const-assertion ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

const ENDPOINTS = { ... } as const; ์™€ ๊ฐ™์ด const-assertion์„ ํ•ด์ฃผ๋ฉด,

 

๊ฐ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ฝ๊ธฐ ์ „์šฉ(readonly)์ด ๋˜๋ฉด์„œ ๊ฐ’์˜ ๋ฆฌํ„ฐ๋Ÿด ํƒ€์ž…์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ฒฐ๊ณผ์ ์œผ๋กœ Endpoint์˜ ํƒ€์ž…์ด ์ค‘์ฒฉ ๊ฐ์ฒด์˜ ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋œ ์œ ๋‹ˆ์–ธ ํƒ€์ž…์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ฒฐ๋ก 

TypeScript์˜ ์ œ๋„ค๋ฆญ, conditional types, typeof, keyof, const-assertion์„ ํ™œ์šฉํ•˜์—ฌ ์ค‘๋ณต ์ฝ”๋“œ ์—†์ด ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์˜ ๊ฐ’๋“ค์„ ํƒ€์ž…์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ฐธ๊ณ 

Conditional Types

๐Ÿ“˜ ๊ฐ์ฒด๋ฅผ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ - keyof / typeof ์‚ฌ์šฉ๋ฒ•

Keyof Type Operator

Typeof Type Operator

readonly and const