์ ์ธ๊ณ ๊ฐ๋ฐ์๋ฅผ ์ํ ์ข ํฉ ๊ฐ์ด๋: ์๋ฐ์คํฌ๋ฆฝํธ ํจํด ๋งค์นญ์ `when` ์ ์ ์ฌ์ฉํ์ฌ ๋ ๊น๋ํ๊ณ ํํ๋ ฅ ์์ผ๋ฉฐ ๊ฒฌ๊ณ ํ ์กฐ๊ฑด๋ถ ๋ก์ง์ ์์ฑํ๋ ๋ฐฉ๋ฒ.
์๋ฐ์คํฌ๋ฆฝํธ์ ์๋ก์ด ์งํ: ํจํด ๋งค์นญ ๊ฐ๋ ์ฒด์ธ์ผ๋ก ๋ณต์กํ ๋ก์ง ๋ง์คํฐํ๊ธฐ
๋์์์ด ์งํํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ ๊นจ๋ํ๊ณ , ๊ฐ๋ ์ฑ ๋์ผ๋ฉฐ, ์ ์ง๋ณด์ํ๊ธฐ ์ข์ ์ฝ๋๋ฅผ ์์ฑํ๋ ค๋ ๋ ธ๋ ฅ์ ๋ณดํธ์ ์ธ ๋ชฉํ์ ๋๋ค. ์์ญ ๋ ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๋ค์ ์กฐ๊ฑด๋ถ ๋ก์ง์ ์ฒ๋ฆฌํ๊ธฐ ์ํด `if/else` ๋ฌธ๊ณผ `switch` ๋ฌธ์ ์์กดํด ์์ต๋๋ค. ์ด ๊ตฌ์กฐ๋ค์ ํจ๊ณผ์ ์ด๊ธด ํ์ง๋ง, ์ฝ๋๊ฐ ๊น๊ฒ ์ค์ฒฉ๋๊ณ ์ ๋ช ๋์ "ํ๋ฉธ์ ํผ๋ผ๋ฏธ๋(pyramid of doom)"๋ฅผ ๋ง๋ค๋ฉฐ ๋ฐ๋ผ๊ฐ๊ธฐ ์ด๋ ค์ด ๋ก์ง์ผ๋ก ์ด์ด์ ธ ๊ธ์ธ ๋ค๋ฃจ๊ธฐ ํ๋ค์ด์ง ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ ์กฐ๊ฑด์ด ๊ฑฐ์ ๋จ์ํ์ง ์์ ๋ณต์กํ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋์ฑ ์ฆํญ๋ฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ณต์กํ ๋ก์ง์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ์ฌ์ ์ํ ํจ๋ฌ๋ค์์ ์ ํ, ๋ฐ๋ก ํจํด ๋งค์นญ(Pattern Matching)์ด ๋ฑ์ฅํ์ต๋๋ค. ํนํ, ์ด ์๋ก์ด ์ ๊ทผ ๋ฐฉ์์ ํ์ ์ ์๋ `when` ์ ์ ์ฌ์ฉํ๋ ๊ฐ๋ ํํ์ ์ฒด์ธ(Guard Expression Chains)๊ณผ ๊ฒฐํฉ๋ ๋ ์์ ํ ๋ฐํ๋ฉ๋๋ค. ์ด ๊ธ์ ์ด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ฌ์ธต์ ์ผ๋ก ํ๊ตฌํ๋ฉฐ, ๋ณต์กํ ์กฐ๊ฑด๋ถ ๋ก์ง์ ๋ฒ๊ทธ์ ํผ๋์ ์์ธ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ช ํ์ฑ๊ณผ ๊ฒฌ๊ณ ํจ์ ๊ธฐ๋ฅ์ผ๋ก ์ด๋ป๊ฒ ๋ณํ์ํฌ ์ ์๋์ง ์์๋ด ๋๋ค.
๊ธ๋ก๋ฒ ์ด์ปค๋จธ์ค ํ๋ซํผ์ ์ํ ๊ด๋ฆฌ ์์คํ ์ ์ค๊ณํ๋ ์ํคํ ํธ๋ , ๋ณต์กํ ๋น์ฆ๋์ค ๊ท์น์ ๊ฐ์ง ๊ธฐ๋ฅ์ ๊ตฌ์ถํ๋ ๊ฐ๋ฐ์๋ , ์ด ๊ฐ๋ ์ ์ดํดํ๋ ๊ฒ์ ์ฐจ์ธ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ ๋ฐ ํต์ฌ์ ๋๋ค.
๋จผ์ , ์๋ฐ์คํฌ๋ฆฝํธ์ ํจํด ๋งค์นญ์ด๋ ๋ฌด์์ผ๊น์?
๊ฐ๋ ์ ์ ์ง๊ฐ๋ฅผ ์ดํดํ๊ธฐ ์ ์, ๊ทธ๊ฒ์ด ๊ธฐ๋ฐํ๋ ๊ธฐ์ด๋ฅผ ๋จผ์ ์์์ผ ํฉ๋๋ค. ํจํด ๋งค์นญ์ ํ์ฌ TC39(์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ํ์คํํ๋ ์์ํ)์์ Stage 1 ์ ์ ๋จ๊ณ์ ์์ผ๋ฉฐ, ์ด๋ ๋จ์ํ "์ด๊ฐ๋ ฅ `switch` ๋ฌธ"์ ํจ์ฌ ๋ฐ์ด๋๋ ๊ฒ์ ๋๋ค.
ํต์ฌ์ ์ผ๋ก, ํจํด ๋งค์นญ์ ๊ฐ์ ํจํด์ ๋ํด ํ์ธํ๋ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ๋ง์ฝ ๊ฐ์ ๊ตฌ์กฐ๊ฐ ํจํด๊ณผ ์ผ์นํ๋ฉด ์ฝ๋๋ฅผ ์คํํ ์ ์์ผ๋ฉฐ, ์ข ์ข ๋ฐ์ดํฐ ์์ฒด์์ ํธ๋ฆฌํ๊ฒ ๊ฐ์ ๊ตฌ์กฐ ๋ถํด(destructuring)ํ ์ ์์ต๋๋ค. ์ด๋ ์ด์ ์ "์ด ๊ฐ์ด X์ ๊ฐ์๊ฐ?"๋ผ๋ ์ง๋ฌธ์์ "์ด ๊ฐ์ด Y์ ํํ๋ฅผ ๊ฐ์ง๊ณ ์๋๊ฐ?"๋ผ๋ ์ง๋ฌธ์ผ๋ก ์ ํํฉ๋๋ค.
์ผ๋ฐ์ ์ธ API ์๋ต ๊ฐ์ฒด๋ฅผ ์๊ฐํด ๋ณด์ธ์:
const apiResponse = { status: 200, data: { userId: 123, name: 'Alex' } };
์ ํต์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ค์๊ณผ ๊ฐ์ด ์ํ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค:
if (apiResponse.status === 200 && apiResponse.data) {
const user = apiResponse.data;
handleSuccess(user);
} else if (apiResponse.status === 404) {
handleNotFound();
} else {
handleGenericError();
}
์ ์๋ ํจํด ๋งค์นญ ๋ฌธ๋ฒ์ ์ด๋ฅผ ์๋นํ ๋จ์ํํ ์ ์์ต๋๋ค:
match (apiResponse) {
with ({ status: 200, data: user }) -> handleSuccess(user),
with ({ status: 404 }) -> handleNotFound(),
with ({ status: 400, error: msg }) -> handleBadRequest(msg),
with _ -> handleGenericError()
}
์ฆ๊ฐ์ ์ธ ์ด์ ์ ํ์ธํด ๋ณด์ธ์:
- ์ ์ธ์ ์คํ์ผ: ์ฝ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ ์ด์ ์ผ๋ก ํ์ธํ ๊ฒ์ธ์ง๊ฐ ์๋๋ผ, ๋ฐ์ดํฐ๊ฐ ์ด๋ป๊ฒ ๋ณด์ฌ์ผ ํ๋์ง๋ฅผ ์ค๋ช ํฉ๋๋ค.
- ํตํฉ๋ ๊ตฌ์กฐ ๋ถํด: `data` ์์ฑ์ ์ฑ๊ณต ์ผ์ด์ค์์ `user` ๋ณ์์ ์ง์ ๋ฐ์ธ๋ฉ๋ฉ๋๋ค.
- ๋ช ํ์ฑ: ์๋๊ฐ ํ๋์ ๋ช ํํฉ๋๋ค. ๋ชจ๋ ๊ฐ๋ฅํ ๋ ผ๋ฆฌ์ ๊ฒฝ๋ก๊ฐ ํจ๊ป ์์นํ์ฌ ์ฝ๊ธฐ ์ฝ์ต๋๋ค.
ํ์ง๋ง ์ด๊ฒ์ ๋น์ฐ์ ์ผ๊ฐ์ ๋ถ๊ณผํฉ๋๋ค. ๋ง์ฝ ๋ก์ง์ด ๊ตฌ์กฐ๋ ๋ฆฌํฐ๋ด ๊ฐ ์ด์์ ๊ฒ์ ์์กดํ๋ค๋ฉด ์ด๋จ๊น์? ์ฌ์ฉ์์ ๊ถํ ์์ค์ด ํน์ ์๊ณ๊ฐ ์ด์์ธ์ง, ๋๋ ์ฃผ๋ฌธ ์ด์ก์ด ํน์ ๊ธ์ก์ ์ด๊ณผํ๋์ง ํ์ธํด์ผ ํ๋ค๋ฉด ์ด๋จ๊น์? ๋ฐ๋ก ์ด ์ง์ ์์ ๊ธฐ๋ณธ์ ์ธ ํจํด ๋งค์นญ์ ํ๊ณ์ ๋ถ๋ชํ๊ณ , ๊ฐ๋ ํํ์์ด ๋น์ ๋ฐํ๊ฒ ๋ฉ๋๋ค.
๊ฐ๋ ํํ์ ์๊ฐ: when ์
๊ฐ๋ ํํ์์ ์ ์์์ `when` ํค์๋๋ฅผ ํตํด ๊ตฌํ๋๋ฉฐ, ํจํด์ด ์ผ์นํ๊ธฐ ์ํด ์ฐธ์ด์ด์ผ ํ๋ ์ถ๊ฐ์ ์ธ ์กฐ๊ฑด์ ๋๋ค. ์ด๋ ๋ฌธ์ง๊ธฐ ์ญํ ์ ํ์ฌ ๊ตฌ์กฐ๊ฐ ์ฌ๋ฐ๋ฅด๋ฉด์ ๋์์ ์์์ ์๋ฐ์คํฌ๋ฆฝํธ ํํ์์ด `true`๋ก ํ๊ฐ๋ ๊ฒฝ์ฐ์๋ง ์ผ์น๋ฅผ ํ์ฉํฉ๋๋ค.
๋ฌธ๋ฒ์ ์๋ฆ๋ต๊ฒ ๊ฐ๋จํฉ๋๋ค:
with pattern when (condition) -> result
๊ฐ๋จํ ์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ซ์๋ฅผ ๋ถ๋ฅํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค:
const value = 42;
const category = match (value) {
with x when (x < 0) -> 'Negative',
with 0 -> 'Zero',
with x when (x > 0 && x <= 10) -> 'Small Positive',
with x when (x > 10) -> 'Large Positive',
with _ -> 'Not a number'
};
// category๋ 'Large Positive'๊ฐ ๋ฉ๋๋ค
์ด ์์ ์์ `x`๋ `value`(42)์ ๋ฐ์ธ๋ฉ๋ฉ๋๋ค. ์ฒซ ๋ฒ์งธ `when` ์ `(x < 0)`์ ๊ฑฐ์ง์ ๋๋ค. `0`์ ๋ํ ์ผ์น๋ ์คํจํฉ๋๋ค. ์ธ ๋ฒ์งธ ์ `(x > 0 && x <= 10)`๋ ๊ฑฐ์ง์ ๋๋ค. ๋ง์ง๋ง์ผ๋ก, ๋ค ๋ฒ์งธ ์ ์ ๊ฐ๋ `(x > 10)`์ด ์ฐธ์ผ๋ก ํ๊ฐ๋๋ฏ๋ก ํจํด์ด ์ผ์นํ๊ณ , ํํ์์ 'Large Positive'๋ฅผ ๋ฐํํฉ๋๋ค.
`when` ์ ์ ํจํด ๋งค์นญ์ ๋จ์ํ ๊ตฌ์กฐ์ ๊ฒ์ฌ์์ ์ ๊ตํ ๋ก์ง ์์ง์ผ๋ก ๊ฒฉ์์์ผ, ์ผ์น ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํด ๋ชจ๋ ์ ํจํ ์๋ฐ์คํฌ๋ฆฝํธ ํํ์์ ์คํํ ์ ์๊ฒ ํฉ๋๋ค.
์ฒด์ธ์ ํ: ๋ณต์กํ๊ณ ์ค์ฒฉ๋๋ ์กฐ๊ฑด ์ฒ๋ฆฌํ๊ธฐ
๊ฐ๋ ํํ์์ ์ง์ ํ ํ์ ๋ณต์กํ ๋น์ฆ๋์ค ๊ท์น์ ๋ชจ๋ธ๋งํ๊ธฐ ์ํด ์ด๋ค์ ํจ๊ป ์ฐ๊ฒฐํ ๋ ๋ํ๋ฉ๋๋ค. `if...else if...else` ์ฒด์ธ์ฒ๋ผ, `match` ๋ธ๋ก์ ์ ๋ค์ ์์ฑ๋ ์์๋๋ก ํ๊ฐ๋ฉ๋๋ค. ํจํด๊ณผ `when` ๊ฐ๋ ๋ชจ๋ ์์ ํ ์ผ์นํ๋ ์ฒซ ๋ฒ์งธ ์ ์ด ์คํ๋๊ณ ํ๊ฐ๋ ์ค์ง๋ฉ๋๋ค.
์ด๋ฌํ ์์ ์๋ ํ๊ฐ๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ฅผ ํตํด ์์ฌ ๊ฒฐ์ ๊ณ์ธต์ ๋ง๋ค๊ณ , ๊ฐ์ฅ ๊ตฌ์ฒด์ ์ธ ๊ฒฝ์ฐ๋ฅผ ๋จผ์ ์ฒ๋ฆฌํ ๋ค์ ๋ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ๋ก ๋์ด๊ฐ ์ ์์ต๋๋ค.
์ค์ฉ ์์ 1: ์ฌ์ฉ์ ์ธ์ฆ ๋ฐ ์ธ๊ฐ
๋ค์ํ ์ฌ์ฉ์ ์ญํ ๊ณผ ์ ๊ทผ ๊ท์น์ด ์๋ ์์คํ ์ ์์ํด ๋ณด์ธ์. ์ฌ์ฉ์ ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค:
const user = {
id: 1,
role: 'editor',
isActive: true,
lastLogin: new Date('2023-10-26T10:00:00Z'),
permissions: ['create', 'edit']
};
์ ๊ทผ ๊ถํ์ ๊ฒฐ์ ํ๋ ๋น์ฆ๋์ค ๋ก์ง์ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค:
- ๋นํ์ฑ ์ฌ์ฉ์๋ ์ฆ์ ์ ๊ทผ์ด ๊ฑฐ๋ถ๋์ด์ผ ํฉ๋๋ค.
- ๊ด๋ฆฌ์๋ ๋ค๋ฅธ ์์ฑ๊ณผ ๊ด๊ณ์์ด ๋ชจ๋ ์ ๊ทผ ๊ถํ์ ๊ฐ์ง๋๋ค.
- 'publish' ๊ถํ์ด ์๋ ํธ์ง์๋ ๊ฒ์ ์ ๊ทผ ๊ถํ์ ๊ฐ์ง๋๋ค.
- ์ผ๋ฐ ํธ์ง์๋ ํธ์ง ์ ๊ทผ ๊ถํ์ ๊ฐ์ง๋๋ค.
- ๊ทธ ์ธ ๋ชจ๋ ์ฌ๋์ ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ ๊ถํ์ ๊ฐ์ง๋๋ค.
์ด๋ฅผ ์ค์ฒฉ๋ `if/else`๋ก ๊ตฌํํ๋ฉด ๋ณต์กํด์ง ์ ์์ต๋๋ค. ๊ฐ๋ ํํ์ ์ฒด์ธ์ ์ฌ์ฉํ๋ฉด ์ผ๋ง๋ ๊น๋ํด์ง๋์ง ๋ณด์ธ์:
const getAccessLevel = (user) => match (user) {
// ๊ฐ์ฅ ๊ตฌ์ฒด์ ์ด๊ณ ์ค์ํ ๊ท์น ๋จผ์ : ๋นํ์ฑ ์ํ ํ์ธ
with { isActive: false } -> 'Access Denied: Account Inactive',
// ๋ค์์ผ๋ก, ๊ฐ์ฅ ๋์ ๊ถํ ํ์ธ
with { role: 'admin' } -> 'Full Administrative Access',
// ๊ฐ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๊ตฌ์ฒด์ ์ธ 'editor' ์ผ์ด์ค ์ฒ๋ฆฌ
with { role: 'editor' } when (user.permissions.includes('publish')) -> 'Publishing Access',
// ์ผ๋ฐ์ ์ธ 'editor' ์ผ์ด์ค ์ฒ๋ฆฌ
with { role: 'editor' } -> 'Standard Editing Access',
// ๋ค๋ฅธ ๋ชจ๋ ์ธ์ฆ๋ ์ฌ์ฉ์๋ฅผ ์ํ ํด๋ฐฑ(Fallback)
with _ -> 'Read-Only Access'
};
์ด ์ฝ๋๋ ๋จ์ง ๋ ์งง์ ๊ฒ์ด ์๋๋ผ, ๋น์ฆ๋์ค ๊ท์น์ ๊ฐ๋ ์ฑ ์๊ณ ์ ์ธ์ ์ธ ํ์์ผ๋ก ์ง์ ๋ฒ์ญํ ๊ฒ์ ๋๋ค. ์์๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ง์ฝ ์ผ๋ฐ์ ์ธ `with { role: 'editor' }` ์ ์ `when` ๊ฐ๋๊ฐ ์๋ ์ ๋ณด๋ค ์์ ๋๋ฉด, ๊ฒ์ ๊ถํ์ด ์๋ ํธ์ง์๋ ๋ ๊ฐ๋จํ ์ผ์ด์ค์ ๋จผ์ ์ผ์นํ๊ธฐ ๋๋ฌธ์ 'Publishing Access' ์์ค์ ์ ๋ ์ป์ง ๋ชปํ ๊ฒ์ ๋๋ค.
์ค์ฉ ์์ 2: ๊ธ๋ก๋ฒ ์ด์ปค๋จธ์ค ์ฃผ๋ฌธ ์ฒ๋ฆฌ
๊ธ๋ก๋ฒ ์ด์ปค๋จธ์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ๋ณต์กํ ์๋๋ฆฌ์ค๋ฅผ ๊ณ ๋ คํด ๋ณด๊ฒ ์ต๋๋ค. ์ฃผ๋ฌธ ์ด์ก, ๋ชฉ์ ์ง ๊ตญ๊ฐ, ๊ณ ๊ฐ ์ํ์ ๋ฐ๋ผ ๋ฐฐ์ก๋น๋ฅผ ๊ณ์ฐํ๊ณ ํ๋ก๋ชจ์ ์ ์ ์ฉํด์ผ ํฉ๋๋ค.
`order` ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค:
const order = {
orderId: 'XYZ-123',
customer: { id: 456, status: 'premium' },
total: 120.50,
destination: { country: 'JP', region: 'Kanto' },
itemCount: 3
};
๊ท์น์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ผ๋ณธ์ ํ๋ฆฌ๋ฏธ์ ๊ณ ๊ฐ์ ยฅ10,000(์ฝ $70) ์ด์ ์ฃผ๋ฌธ ์ ๋ฌด๋ฃ ํน๊ธ ๋ฐฐ์ก์ ๋ฐ์ต๋๋ค.
- $200 ์ด์ ์ฃผ๋ฌธ ์ ์ ์ธ๊ณ ๋ฌด๋ฃ ๋ฐฐ์ก์ ๋ฐ์ต๋๋ค.
- EU ๊ตญ๊ฐ๋ก์ ์ฃผ๋ฌธ์ โฌ15์ ๊ณ ์ ์๊ธ์ด ๋ถ๊ณผ๋ฉ๋๋ค.
- ๋ฏธ๊ตญ ๋ด ์ฃผ๋ฌธ์ $50 ์ด์์ผ ๊ฒฝ์ฐ ๋ฌด๋ฃ ํ์ค ๋ฐฐ์ก์ ๋ฐ์ต๋๋ค.
- ๊ธฐํ ๋ชจ๋ ์ฃผ๋ฌธ์ ๋์ ๋ฐฐ์ก๋น ๊ณ์ฐ๊ธฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด ๋ก์ง์ ์ฌ๋ฌ ๊ฐ์, ๋๋ก๋ ์ค์ฒฉ๋๋ ์์ฑ์ ํฌํจํฉ๋๋ค. ๊ฐ๋ ์ฒด์ธ์ด ์๋ `match` ๋ธ๋ก์ ์ด๋ฅผ ๊ด๋ฆฌ ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค:
const getShippingInfo = (order) => match (order) {
// ๊ฐ์ฅ ๊ตฌ์ฒด์ ์ธ ๊ท์น: ํน์ ๊ตญ๊ฐ์ ํ๋ฆฌ๋ฏธ์ ๊ณ ๊ฐ ๋ฐ ์ต์ ์ฃผ๋ฌธ ์ด์ก
with { customer: { status: 'premium' }, destination: { country: 'JP' }, total: t } when (t > 70) -> { type: 'Express', cost: 0, notes: '์ผ๋ณธ ํ๋ฆฌ๋ฏธ์ ๊ณ ๊ฐ ๋ฌด๋ฃ ๋ฐฐ์ก' },
// ์ผ๋ฐ์ ์ธ ๊ณ ์ก ์ฃผ๋ฌธ ๊ท์น
with { total: t } when (t > 200) -> { type: 'Standard', cost: 0, notes: '์ ์ธ๊ณ ๋ฌด๋ฃ ๋ฐฐ์ก' },
// EU ์ง์ญ ๊ท์น
with { destination: { country: c } } when (['DE', 'FR', 'ES', 'IT'].includes(c)) -> { type: 'Standard', cost: 15, notes: 'EU ๊ณ ์ ์๊ธ' },
// ๋ฏธ๊ตญ ๋ด ๋ฐฐ์ก ํํ
with { destination: { country: 'US' }, total: t } when (t > 50) -> { type: 'Standard', cost: 0, notes: '๋ฏธ๊ตญ ๋ด ๋ฌด๋ฃ ๋ฐฐ์ก' },
// ๊ทธ ์ธ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ์ํ ํด๋ฐฑ
with _ -> { type: 'Calculated', cost: calculateDynamicRate(order.destination), notes: 'ํ์ค ๊ตญ์ ์๊ธ' }
};
์ด ์์ ๋ ํจํด ๊ตฌ์กฐ ๋ถํด์ ๊ฐ๋๋ฅผ ๊ฒฐํฉํ๋ ์ง์ ํ ํ์ ๋ณด์ฌ์ค๋๋ค. ๊ฐ์ฒด์ ํ ๋ถ๋ถ(์: `{ destination: { country: c } }`)์ ๊ตฌ์กฐ ๋ถํดํ๋ฉด์ ์์ ํ ๋ค๋ฅธ ๋ถ๋ถ(์: `{ total: t }`์์ ์จ `when (t > 50)`)์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฐ์ดํฐ ์ถ์ถ๊ณผ ์ ํจ์ฑ ๊ฒ์ฌ์ ๊ณต์กด์ ์ ํต์ ์ธ `if/else` ๊ตฌ์กฐ์์๋ ํจ์ฌ ๋ ์ฅํฉํ๊ฒ ์ฒ๋ฆฌ๋ฉ๋๋ค.
๊ฐ๋ ํํ์ vs. ์ ํต์ ์ธ `if/else` ๋ฐ `switch`
์ด ๋ณํ๋ฅผ ์์ ํ ์ดํดํ๊ธฐ ์ํด ํจ๋ฌ๋ค์์ ์ง์ ๋น๊ตํด ๋ณด๊ฒ ์ต๋๋ค.
๊ฐ๋ ์ฑ๊ณผ ํํ๋ ฅ
๋ณต์กํ `if/else` ์ฒด์ธ์ ์ข ์ข ๋ณ์ ์ ๊ทผ์ ๋ฐ๋ณตํ๊ณ ์กฐ๊ฑด๊ณผ ๊ตฌํ ์ธ๋ถ ์ฌํญ์ ์๋๋ก ๊ฐ์ํฉ๋๋ค. ํจํด ๋งค์นญ์ "๋ฌด์"(ํจํด)์ "์"(๊ฐ๋)์ "์ด๋ป๊ฒ"(๊ฒฐ๊ณผ)๋ก๋ถํฐ ๋ถ๋ฆฌํฉ๋๋ค.
์ ํต์ ์ธ `if/else` ์ง์ฅ:
function processRequest(req) {
if (req.method === 'POST') {
if (req.body && req.body.data) {
if (req.headers['content-type'] === 'application/json') {
if (req.user && req.user.isAuthenticated) {
// ... ์ค์ ๋ก์ง์ ์ฌ๊ธฐ์
} else { /* ๋ฏธ์ธ์ฆ ์ฒ๋ฆฌ */ }
} else { /* ์๋ชป๋ content-type ์ฒ๋ฆฌ */ }
} else { /* body ์์ ์ฒ๋ฆฌ */ }
} else if (req.method === 'GET') { /* ... */ }
}
๊ฐ๋๋ฅผ ์ฌ์ฉํ ํจํด ๋งค์นญ:
function processRequest(req) {
return match (req) {
with { method: 'POST', body: { data }, user } when (user?.isAuthenticated && req.headers['content-type'] === 'application/json') -> {
return handleCreation(data, user);
},
with { method: 'POST' } -> {
return createBadRequestResponse('Invalid POST request');
},
with { method: 'GET', params: { id } } -> {
return handleRead(id);
},
with _ -> createMethodNotAllowedResponse()
};
}
`match` ๋ฒ์ ์ ๋ ํํํ๊ณ , ์ ์ธ์ ์ด๋ฉฐ, ๋๋ฒ๊น ํ๊ณ ํ์ฅํ๊ธฐ๊ฐ ํจ์ฌ ์ฝ์ต๋๋ค.
๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ถํด ๋ฐ ๋ฐ์ธ๋ฉ
ํจํด ๋งค์นญ์ ํต์ฌ์ ์ธ ์ธ์ฒด๊ณตํ์ ์ฅ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์กฐ ๋ถํดํ๊ณ ๋ฐ์ธ๋ฉ๋ ๋ณ์๋ฅผ ๊ฐ๋ ๋ฐ ๊ฒฐ๊ณผ ์ ์์ ์ง์ ์ฌ์ฉํ ์ ์๋ค๋ ์ ์ ๋๋ค. `if` ๋ฌธ์์๋ ๋จผ์ ์์ฑ์ ์กด์ฌ๋ฅผ ํ์ธํ ๋ค์ ์ ๊ทผํด์ผ ํฉ๋๋ค. ํจํด ๋งค์นญ์ ์ด ๋ ๊ฐ์ง๋ฅผ ํ ๋ฒ์ ์ฐ์ํ ๋จ๊ณ๋ก ์ํํฉ๋๋ค.
์ ์์ ์์ `data`์ `id`๊ฐ `req` ๊ฐ์ฒด์์ ์์ฝ๊ฒ ์ถ์ถ๋์ด ํ์ํ ๊ณณ์ ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅํด์ง ๊ฒ์ ์ฃผ๋ชฉํ์ธ์.
์ฒ ์ ์ฑ ๊ฒ์ฌ(Exhaustiveness Checking)
์กฐ๊ฑด๋ถ ๋ก์ง์์ ํํ ๋ฒ๊ทธ์ ์์ธ์ ์์ด๋ฒ๋ฆฐ ์ผ์ด์ค์ ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ์ ์์ ์ปดํ์ผ ํ์์ ์ฒ ์ ์ฑ ๊ฒ์ฌ๋ฅผ ์๋ฌดํํ์ง๋ ์์ง๋ง, ์ด๋ ์ ์ ๋ถ์ ๋๊ตฌ(TypeScript๋ ๋ฆฐํฐ ๋ฑ)๊ฐ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ ๊ธฐ๋ฅ์ ๋๋ค. `with _` ํฌ๊ด์ ์ผ์ด์ค๋ ์๋์ ์ผ๋ก ๋ค๋ฅธ ๋ชจ๋ ๊ฐ๋ฅ์ฑ์ ์ฒ๋ฆฌํ๊ณ ์์์ ๋ช ์์ ์ผ๋ก ๋ง๋ค์ด, ์์คํ ์ ์๋ก์ด ์ํ๊ฐ ์ถ๊ฐ๋์์ง๋ง ๋ก์ง์ด ์ด๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์ ๋ฐ์ดํธ๋์ง ์์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
๊ณ ๊ธ ๊ธฐ์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ฐ๋ ํํ์ ์ฒด์ธ์ ์ง์ ์ผ๋ก ๋ง์คํฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ณ ๊ธ ์ ๋ต์ ๊ณ ๋ คํ์ธ์.
1. ์์๊ฐ ์ค์ํฉ๋๋ค: ๊ตฌ์ฒด์ ์ธ ๊ฒ์์ ์ผ๋ฐ์ ์ธ ๊ฒ์ผ๋ก
์ด๊ฒ์ด ํฉ๊ธ๋ฅ ์ ๋๋ค. ํญ์ ๊ฐ์ฅ ๊ตฌ์ฒด์ ์ด๊ณ ์ ํ์ ์ธ ์ ์ `match` ๋ธ๋ก์ ๋งจ ์์ ๋ฐฐ์นํ์ธ์. ์์ธํ ํจํด๊ณผ ์ ํ์ ์ธ `when` ๊ฐ๋๊ฐ ์๋ ์ ์ด ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ๋งค์นํ ์ ์๋ ๋ ์ผ๋ฐ์ ์ธ ์ ๋ณด๋ค ๋จผ์ ์์ผ ํฉ๋๋ค.
2. ๊ฐ๋๋ ์์ํ๊ฒ ์ ์งํ๊ณ ๋ถ์ ํจ๊ณผ(Side Effect)๊ฐ ์๋๋ก ํ์ธ์
A `when` ์ ์ ์์ ํจ์์ฌ์ผ ํฉ๋๋ค: ๋์ผํ ์ ๋ ฅ์ด ์ฃผ์ด์ง๋ฉด ํญ์ ๋์ผํ ๋ถ๋ฆฌ์ธ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๊ณ ๊ด์ฐฐ ๊ฐ๋ฅํ ๋ถ์ ํจ๊ณผ(API ํธ์ถ์ด๋ ์ ์ญ ๋ณ์ ์์ ๋ฑ)๊ฐ ์์ด์ผ ํฉ๋๋ค. ๊ทธ๊ฒ์ ์๋ฌด๋ ์กฐ๊ฑด์ ํ์ธํ๋ ๊ฒ์ด์ง, ๋์์ ์คํํ๋ ๊ฒ์ด ์๋๋๋ค. ๋ถ์ ํจ๊ณผ๋ ๊ฒฐ๊ณผ ํํ์( `->` ๋ค์ ๋ถ๋ถ)์ ์ํฉ๋๋ค. ์ด ์์น์ ์๋ฐํ๋ฉด ์ฝ๋๋ฅผ ์์ธกํ๊ธฐ ์ด๋ ต๊ณ ๋๋ฒ๊น ํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค.
3. ๋ณต์กํ ๊ฐ๋์๋ ํฌํผ ํจ์๋ฅผ ์ฌ์ฉํ์ธ์
๊ฐ๋ ๋ก์ง์ด ๋ณต์กํ๋ค๋ฉด `when` ์ ์ ์ด์ง๋ฝํ์ง ๋ง์ธ์. ๋ก์ง์ ์ ์ด๋ฆ ๋ถ์ฌ์ง ํฌํผ ํจ์๋ก ์บก์ํํ์ธ์. ์ด๋ ๊ฐ๋ ์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ํฅ์์ํต๋๋ค.
๊ฐ๋ ์ฑ์ด ๋ฎ์ ๊ฒฝ์ฐ:
with { event: 'purchase', timestamp: t } when (new Date().getTime() - new Date(t).getTime() < 60000 && someOtherCondition) -> ...
๊ฐ๋ ์ฑ์ด ๋์ ๊ฒฝ์ฐ:
const isRecentPurchase = (event) => {
const oneMinuteAgo = new Date().getTime() - 60000;
return new Date(event.timestamp).getTime() > oneMinuteAgo && someOtherCondition;
};
...
with event when (isRecentPurchase(event)) -> ...
4. ๋ณต์กํ ํจํด๊ณผ ๊ฐ๋๋ฅผ ๊ฒฐํฉํ์ธ์
ํผํฉํ๊ณ ์ผ์น์ํค๋ ๊ฒ์ ๋๋ ค์ํ์ง ๋ง์ธ์. ๊ฐ์ฅ ๊ฐ๋ ฅํ ์ ์ ๊น์ ๊ตฌ์กฐ์ ๊ตฌ์กฐ ๋ถํด์ ์ ๋ฐํ ๊ฐ๋ ์ ์ ๊ฒฐํฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ ๋งค์ฐ ํน์ ํ ๋ฐ์ดํฐ ํํ์ ์ํ๋ฅผ ์ ํํ ์ฐพ์๋ผ ์ ์์ต๋๋ค.
// 'billing' ๋ถ์์ VIP ์ฌ์ฉ์์ ๋ํ ์ง์ ํฐ์ผ์ด 3์ผ ์ด์ ์ด๋ ค ์๋ ๊ฒฝ์ฐ ๋งค์นญ
with { user: { status: 'vip' }, department: 'billing', created: c } when (isOlderThan(c, 3, 'days')) -> escalateToTier2(ticket)
์ฝ๋ ๋ช ํ์ฑ์ ๋ํ ๊ธ๋ก๋ฒ ๊ด์
๋ค๋ฅธ ๋ฌธํ์ ์๊ฐ๋์์ ์์ ํ๋ ๊ตญ์ ํ์๊ฒ ์ฝ๋์ ๋ช ํ์ฑ์ ์ฌ์น๊ฐ ์๋๋ผ ํ์์ ๋๋ค. ๋ณต์กํ๊ณ ๋ช ๋ น์ ์ธ ์ฝ๋๋ ํด์ํ๊ธฐ ์ด๋ ค์ธ ์ ์์ผ๋ฉฐ, ํนํ ์ค์ฒฉ๋ ์กฐ๊ฑด๋ถ ํํ์ ๋์์ค๋ฅผ ํ์ ํ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช์ ์ ์๋ ๋น์์ด๋ฏผ์๊ฒ๋ ๋์ฑ ๊ทธ๋ ์ต๋๋ค.
ํจํด ๋งค์นญ์ ์ ์ธ์ ์ด๊ณ ์๊ฐ์ ์ธ ๊ตฌ์กฐ๋ก ์ธ์ด ์ฅ๋ฒฝ์ ๋ ํจ๊ณผ์ ์ผ๋ก ๋์ด์ญ๋๋ค. `match` ๋ธ๋ก์ ์ง๋ฆฌํ์ ๊ฐ์ต๋๋ค. ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋ ฅ๊ณผ ๊ทธ์ ์์ํ๋ ์ถ๋ ฅ์ ๋ช ํํ๊ณ ๊ตฌ์กฐํ๋ ๋ฐฉ์์ผ๋ก ๋์ดํฉ๋๋ค. ์ด๋ฌํ ์์ฒด ๋ฌธ์ํ ํน์ฑ์ ๋ชจํธ์ฑ์ ์ค์ด๊ณ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๊ธ๋ก๋ฒ ๊ฐ๋ฐ ์ปค๋ฎค๋ํฐ์ ๋ ํฌ๊ด์ ์ด๊ณ ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
๊ฒฐ๋ก : ์กฐ๊ฑด๋ถ ๋ก์ง์ ํจ๋ฌ๋ค์ ์ ํ
์์ง ์ ์ ๋จ๊ณ์ ์์ง๋ง, ๊ฐ๋ ํํ์์ ๊ฐ์ถ ์๋ฐ์คํฌ๋ฆฝํธ์ ํจํด ๋งค์นญ์ ์ธ์ด์ ํํ๋ ฅ์ ํ ๋จ๊ณ ๋์ด์ฌ๋ฆฌ๋ ๊ฐ์ฅ ์ค์ํ ๋ฐ์ ์ค ํ๋๋ฅผ ๋ํํฉ๋๋ค. ์ด๋ ์์ญ ๋ ๋์ ์ฐ๋ฆฌ ์ฝ๋๋ฅผ ์ง๋ฐฐํด ์จ `if/else` ๋ฐ `switch` ๋ฌธ์ ๋ํ ๊ฒฌ๊ณ ํ๊ณ ์ ์ธ์ ์ด๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ ๋์์ ์ ๊ณตํฉ๋๋ค.
๊ฐ๋ ํํ์ ์ฒด์ธ์ ๋ง์คํฐํจ์ผ๋ก์จ ๋ค์์ ํ ์ ์์ต๋๋ค:
- ๋ณต์กํ ๋ก์ง ํํํ: ๊น์ ์ค์ฒฉ์ ์ ๊ฑฐํ๊ณ ํํํ๊ณ ๊ฐ๋ ์ฑ ์๋ ์์ฌ ๊ฒฐ์ ํธ๋ฆฌ๋ฅผ ๋ง๋ญ๋๋ค.
- ์์ฒด ๋ฌธ์ํ ์ฝ๋ ์์ฑ: ์ฝ๋๊ฐ ๋น์ฆ๋์ค ๊ท์น์ ์ง์ ์ ์ผ๋ก ๋ฐ์ํ๋๋ก ๋ง๋ญ๋๋ค.
- ๋ฒ๊ทธ ๊ฐ์: ๋ชจ๋ ๋ ผ๋ฆฌ์ ๊ฒฝ๋ก๋ฅผ ๋ช ์์ ์ผ๋ก ๋ง๋ค๊ณ ๋ ๋์ ์ ์ ๋ถ์์ ๊ฐ๋ฅํ๊ฒ ํ์ฌ ๋ฒ๊ทธ๋ฅผ ์ค์ ๋๋ค.
- ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ๊ตฌ์กฐ ๋ถํด ๊ฒฐํฉ: ๋ฐ์ดํฐ์ ํํ์ ์ํ๋ฅผ ๋จ์ผ ์์ ์ผ๋ก ์ฐ์ํ๊ฒ ํ์ธํฉ๋๋ค.
๊ฐ๋ฐ์๋ก์, ์ด์ ํจํด์ผ๋ก ์๊ฐํ๊ธฐ ์์ํ ๋์ ๋๋ค. ๊ณต์ TC39 ์ ์์ ํ์ํ๊ณ , Babel ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ์ฌ ์คํํ๋ฉฐ, ์กฐ๊ฑด๋ถ ๋ก์ง์ด ๋ ์ด์ ํ์ด์ผ ํ ๋ณต์กํ ๊ฑฐ๋ฏธ์ค์ด ์๋๋ผ ์ ํ๋ฆฌ์ผ์ด์ ํ๋์ ๋ช ํํ๊ณ ํํ๋ ฅ ์๋ ์ง๋๊ฐ ๋๋ ๋ฏธ๋๋ฅผ ์ค๋นํ์๊ธฐ ๋ฐ๋๋๋ค.