์ค์ฒฉ๋ ๊ฐ์ฒด์์ ๊ฐ๋ง ๋ฝ์์ ํ์ ์ผ๋ก ๋ง๋ค ์ ์์๊น?
๐ค
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์ ํ์ฉํ์ฌ ์ค๋ณต ์ฝ๋ ์์ด ์ค์ฒฉ๋ ๊ฐ์ฒด์ ๊ฐ๋ค์ ํ์ ์ผ๋ก ํ์ฉํ ์ ์์ต๋๋ค.
์ฐธ๊ณ
๐ ๊ฐ์ฒด๋ฅผ ํ์ ์ผ๋ก ๋ณํ - keyof / typeof ์ฌ์ฉ๋ฒ
'Language > TypeScript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[TypeScript] Class vs Interface vs Type ์ฐจ์ด์ ์ ๋ฆฌ (0) | 2024.08.07 |
---|---|
[TypeScript] Declaration File & JSDoc (1) | 2024.08.07 |
[TypeScript] TypeScript ํ์ ์ ๋ฆฌ (0) | 2024.08.07 |
[TypeScript] TypeScript ์๋์ผ๋ก ์ค์ ํ๊ธฐ (0) | 2024.08.07 |
[TypeScript] TypeScript ์ฅ์ ๊ณผ ํน์ง (0) | 2024.08.05 |