avatar
Published on

Typescript์˜ Immutability

Author
  • avatar
    Name
    yceffort

Table of Contents

๋ถˆ๋ณ€์„ฑ

Immutability(์ดํ•˜ ๋ถˆ๋ณ€์„ฑ)์ด๋ž€, ์ดˆ๊ธฐ์— ํ• ๋‹น ํ•œ ์ดํ›„์— ๋” ์ด์ƒ ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ๋ชจ๋“  ๊ฐ์ฒด์— ์ด ๋ถˆ๋ณ€์„ฑ์„ ์ ์šฉํ•˜๋ฉด, ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ, ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ดํ•ด๋„ ์ฆ๊ฐ€, ์Šค๋ ˆ๋“œ์˜ ์•ˆ์ •์„ฑ ๋“ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ถˆ๋ณ€์„ฑ์„ ๋…ผํ•˜๊ธฐ์— ์•ž์„œ

์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ณ์˜ ์ „ํ†ต์ ์ธ ๊ฐ์ฒด์ง€ํ–ฅ ์ ‘๊ทผ๋ฒ•์—์„œ, ๋ชจ๋“  ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋Š” ํŠน์ • ์ธ์Šคํ„ด์Šค์—๋งŒ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ƒํƒœ์˜ ์ดˆ๊ธฐํ™”๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž์—์„œ ๋ฐœ์ƒํ•˜๋ฉฐ, ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ ํ•ด๋‹น ์ƒํƒœ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ฌด๋ฆฌ ์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ฐ’์˜ ๋ณ€ํ™”๊ฐ€ ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„, ํด๋ž˜์Šค์˜ ์ƒํƒœ๊ฐ€ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ธก๋ฉด์€ ํด๋ž˜์Šค์— ์˜์กดํ•˜๋Š” ์ฝ”๋“œ์˜ ๊ตฌ์กฐ์— ํฌ๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.

์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ฐ’ ๋ณ€์ด์— ๋”ฐ๋ฅธ ๋‹จ์ ์„ ์ดํ•ดํ•˜๊ธฐ์— ์•ž์„œ, ๋‘๊ฐœ์˜ ํƒ€์ž…์˜ ํ•จ์ˆ˜๋ฅผ ๋จผ์ € ์†Œ๊ฐœํ•˜๊ณ ์žํ•œ๋‹ค.

  • synchronous(๋™๊ธฐ): ํ˜„ํƒœ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์—์„œ ์ฆ‰์‹œ ์‹คํ–‰๋˜์–ด ๋ฆฌํ„ดํ•œ๋‹ค
  • asynchronous(๋น„๋™๊ธฐ) ํ˜„์žฌ ์‹คํ–‰์ปจํ…์ŠคํŠธ์—์„œ ๋Œ€๊ธฐํ•˜๋ฉฐ, ๋‹ค๋ฅธ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜์–ด ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.

์ฝ”๋“œ ์‹คํ–‰ํ™˜๊ฒฝ์— ๋”ฐ๋ผ, ํด๋กœ์ ธ๊ฐ€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ๋๋‚˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ํ˜ธ์ถœํ•˜๋ฉฐ, ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์ƒํƒœ๊ฐ’์„ ๋ฐ”๊พผ๋‹ค๋ฉด, ํด๋กœ์ ธ ๋‚ด๋ถ€์—์„œ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ์— ๋Œ€ํ•ด ์‹ ๋ขฐ์„ฑ์„ ๊ฐ€์งˆ ์ˆ˜๊ฐ€ ์—†๋‹ค. ๋™๊ธฐํ˜ธ์ถœ์—๋Š” ์ด๋Ÿฌํ•œ ๋ถ€์ˆ˜ํšจ๊ณผ๊ฐ€ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํŠน์ • ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ํ˜ธ์ถœ์€, ๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ๋‚ด๋ถ€์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด๋ฒ„๋ฆฐ๋‹ค๋ฉด ๋ชจ๋‘ ๋ฌดํšจ๊ฐ€ ๋˜๋ฒ„๋ฆฐ๋‹ค.

๋‘๋ฒˆ์งธ๋กœ, ๋ถˆ๋ณ€ํ•จ์ˆ˜์™€ ๋ณ€์ดํ•จ์ˆ˜๋ฅผ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•œ๋‹ค. ๋ถˆ๋ณ€ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ๋‹จํ•˜๋‚˜์˜ ํšจ๊ณผ(effect) ๋งŒ ๊ฐ€์ง„๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณ€์ด ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์—์„œ ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ณ , ์ด๋Š” ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ๋ถˆ๋Ÿฌ ์ผ์œผํ‚ค๊ฒŒ ๋œ๋‹ค.

์„ธ๋ฒˆ์งธ๋กœ, ๊ฐ์ฒด์ง€ํ–ฅ ์•„ํ‚คํ…์ณ์—์„œ ๊ฐœ๋ฐœ์ž๋Š” ์–ด๋–ค ํด๋ž˜์Šค์—์„œ๋“  getter์™€ setter๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. getter๋Š” ๋‹จ์ˆœํžˆ ์ƒํƒœ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ํ–‰์œ„๋กœ, ๋ถˆ๋ณ€ํ•จ์ˆ˜๋กœ ๋™์ž‘ํ•œ๋‹ค. ๋ฐ˜๋ฉด์— setter๋Š” ์ƒํƒœ์— ๊ฐ’์„ ๋ถ€์—ฌํ•˜๋ฏ€๋กœ ๋ณ€์ด๋ฅผ ์ด๋ฅดํ‚ค๊ฒŒ ๋œ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ฐœ๋…์„ ๋‹ค ํ†ตํ‹€์–ด์„œ, ๊ฐœ๋ฐœ์ž๋Š” ์ฝ”๋“œ์˜ ๋‹ค์–‘ํ•œ ์œ„์น˜์™€ ๋‹ค์–‘ํ•œ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ (์Šค๋ ˆ๋“œ, ์ฝœ๋ฐฑ ๋ชจ๋‘)์—์„œ ๋ณ€์ด๋˜๋Š” ์ƒํƒœ๊ฐ€ ๋งŒ๋“œ๋Š” ์ž ์žฌ์ ์ธ ๋ณต์žก์„ฑ์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฏธ๋ž˜์˜ ๋ณต์žกํ•จ์œผ๋กœ ๋ถ€ํ„ฐ ์ƒํƒœ๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ์ง€์นจ์„ ๋”ฐ๋ฅด์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋””๋ฒ„๊น…์ด๋‚˜ ์ถ”๋ก ์ด ๋ณต์žกํ•œ ์‹œ์Šคํ…œ์—์„œ ๊ณจ์นซ๊ฑฐ๋ฆฌ๋กœ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ๋ถˆ๋ณ€์„ฑ์„ ์ ์šฉํ•˜๋Š” ๊ทผ๋ณธ์ ์ธ ์ด์œ , ํ”„๋กœ์ ํŠธ์˜ ์›ํ™œํ•œ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•œ ์˜์š•์„ ๋–จ์–ด ๋œจ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ถˆ๋ณ€์„ฑ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฉ€ํ‹ฐ ํŒจ๋Ÿฌ๋‹ค์ž„ ์–ธ์–ด์ด๋ฏ€๋กœ, ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ•จ์ˆ˜ํ˜• ์‚ฌ๊ณ ๋ฅผ ๊ฐ•์š”ํ•˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ธก๋ฉด์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ธ์–ด ์ž์ฒด์ ์œผ๋กœ๋Š” ์•ž์„œ ์–ธ๊ธ‰ํ•œ ๋ถˆ๋ณ€์„ฑ์„ ์ง€์›ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด ๋ช‡๊ฐ€์ง€ ๋ฌธ์ž์—ด์„ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค. ๋ถˆ๋ณ€์„ฑ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ํ•ด๋‹น ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด์— ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๋Š” ์ž‘์—…์„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค.

Primitive, wrapper type

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ๋ช‡๊ฐ€์ง€ ์›์‹œํƒ€์ž… (boolean number bigint string symbol null undefined) ์ด ์žˆ๋‹ค. ์ด๋“ค ๋ชจ๋‘ ๋ฉ”์†Œ๋“œ๊ฐ€ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๋ถˆ๋ณ€์˜ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋ฉฐ, ์ด๋Š” ํ•จ์ˆ˜๋กœ ์ด๋“ค์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๋ถ€์ˆ˜ํšจ๊ณผ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ž๊ฐ€ 5๊ฐ€์ง€ wrapper (object)์— ๋Œ€ํ•ด ์ž˜ ์•Œ์ง€ ๋ชปํ•œ๋‹ค. (Boolean Number BigInt String Symbol) ์ด๋Š” ์–ธ์–ด๊ฐ€ ์›์‹œํƒ€์ž…๊ณผ ๋ž˜ํผ ๊ฐ์ฒด์— ์ƒํ˜ธ๊ตํ™˜(interchangeable)์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ชจ๋“  ๊ฐ์ฒด (์›์‹œํƒ€์ž…์ด ์•„๋‹Œ๊ฒƒ, ํ•จ์ˆ˜ ํฌํ•จ)๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ ๊ฐ’์˜ ๋ณ€ํ™”๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ์ฒด๋Š”, ๊ทธ ์ •์˜์— ๋”ฐ๋ผ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ด๋Ÿฌํ•œ ํ”„๋กœํ† ํƒ€์ž…์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ๊ฐ์ฒด์˜ ๋™์ž‘์„ ๋ฐ”๊ฟ€ ์ˆ˜๋„ ์žˆ๋‹ค.

๋ณ€์ˆ˜ ์„ ์–ธ

๊ฐœ๋ฐœ์ž๋“ค์€ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•ด์„œ let const๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ let์˜ ์‚ฌ์šฉ์„ ์ž์ œํ•˜๋„๋ก ํ•˜๊ฒŒ ํ•˜๋Š” ํŽธ์ด๋‹ค. let์€ ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ๋ช‡๋ฒˆ์ด๊ณ  ์žฌํ• ๋‹น์ด ์ด๋ฃจ์–ด์ ธ์„œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฒฝํ—˜์ด ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์€, ๋ณ€์ˆ˜์˜ ์žฌ ํ• ๋‹น์„ ์—ฌ๋Ÿฌ ํ•จ์ˆ˜์— ๋‚˜๋ˆ„๊ณ , ์ด๋ฅผ ๋ณ„๋„๋กœ ๋ฆฌํ„ดํ•˜๋„๋ก ๋ฆฌํŒฉํ† ๋ง ํ•œ๋‹ค.

๊ฐ์ฒด ๋™๊ฒฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฐ์ฒด๋ฅผ ์–•๊ฒŒ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์–•๊ฒŒ๋ผ๋Š” ๋ง์— ์ฃผ๋ชฉํ•˜์ž. ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์—์„œ๋Š” ์ด๋Ÿฌํ•œ ํŠน์„ฑ์ด ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. Object.freeze ํ•จ์ˆ˜๋Š” ๋ง๊ทธ๋Œ€๋กœ ๊ฐ์ฒด๋ฅผ ๋™๊ฒฐ์‹œ์ผœ ์ฃผ๋ฉฐ, ์ด๋ฅผ ์–•๊ฒŒ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค.

const obj = {
  a: {
    b: 1,
  },
}
Object.freeze(obj)
obj.a = null // ์•ˆ๋จ!
obj.b = true // ์•ˆ๋จ!
obj.a.b = 2 // ๋จ?!!

Object.freeze๋Š” ๊ฐ์ฒด์˜ ๋Ÿฐํƒ€์ž„ ์ˆ˜์ค€์—์„œ ์ง์ ‘์ ์œผ๋กœ ์ œํ•œ์„ ๊ฑด๋‹ค. ๊ฐ์ฒด๋ฅผ ๋™๊ฒฐํ•˜๋ฉด, writable๊ณผ configurable๊ฐ€ false๋กœ ๋ฐ”๋€๋‹ค. ์ด-๊ธ€์„ ์ฐธ๊ณ ํ•˜์ž. ์•„๋ฌดํŠผ, ๊ฐ์ฒด๋ฅผ ์ •๋ง๋กœ ๊นŠ๊ฒŒ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š”, ๋ณ„๋„๋กœ ์จ๋“œ ํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์Šค์Šค๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

ํ•จ์ˆ˜ ์†์„ฑ

ํ•จ์ˆ˜ ๋˜ํ•œ ๊ฐ์ฒด๋ผ๋Š” ์ ์—์„œ, ๋ชจ๋“  ํ•จ์ˆ˜ ์†์„ฑ์€ ์ž ์žฌ์ ์œผ๋กœ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ๊ฐ์ฒด๋ฅผ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ์— ์˜ํ•ด์„œ ์ผ์–ด๋‚˜๊ณ , ์ „๋‹ฌ๋œ ์›์‹œํƒ€์ž…์€ ๊ฐ’์— ์˜ํ•ด ์ผ์–ด๋‚œ๋‹ค๊ณ  ๋ณด์ž. ํฅ๋ฏธ๋กญ๊ฒŒ๋„(ํ˜น์€ ๊ท€์ฐฎ๊ฒŒ๋„) ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ•จ์ˆ˜์˜ arguments๋ฅผ ์žฌํ• ๋‹น ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š”๋ฐ, ์ด๋Š” ํด๋กœ์ ธ ๊ทœ์น™์— ๋”ฐ๋ผ ํ•จ์ˆ˜ ๋ฒ”์œ„ ๋ฐ–์—์„œ๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๋ถˆ๋ณ€์„ฑ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๋ถˆ๋ณ€์„ฑ๊ณผ ๊ด€๋ จ๋˜์–ด ๋†€๋ผ์šด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. compile-time ํƒ€์ž… ์‹œ์Šคํ…œ์„ ํ™œ์šฉํ•˜์—ฌ, ์—”๋“œ ์œ ์ €์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ์ฝ”๋“œ์˜ ์–‘์„ ์ค„์ด๊ณ , ๋Ÿฐํƒ€์ž„ ๋ ˆ๋ฒจ์— ๋Œ€ํ•œ ์ œํ•œ์„ ๋ช…์‹œํ• ์ˆ˜๋„ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๋ถˆ๋ณ€์„ฑ์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด, readonly ์†์„ฑ์˜ ๊ฐœ๋…์„ ๋„์ž…ํ•œ๋‹ค.

readonly

readonly๋Š” ํƒ€์ž…๊ณผ ์ธํ„ฐํŽ˜์ด์Šค, ํด๋ž˜์Šค ์†์„ฑ๊ณผ ์ƒ์„ฑ์ž์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—์„œ ์ƒ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด, ๊ฐ์ฒด ์˜ค์ง ๋‹จํ•œ๋ฒˆ, ๊ฐ์ฒด ์ƒ์„ฑ์ค‘์—๋งŒ ํ• ๋‹น๋œ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ์†์„ฑ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

readonly์˜ ์‚ฌ์šฉ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์–•์€ ๋ถˆ๋ณ€์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.

Object.freeze<T>๊ฐ€ ๊ฒฐ๊ณผ๋กœ Readonly<T>๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ฃผ๋ชฉํ•˜์ž. ์ด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ freeze์™€ readonly์‚ฌ์ด์˜ ์ผ์ข…์˜ ์—ฐ๊ฒฐ๊ณ ๋ฆฌ๋‹ค.

๊นŠ์€ ๋ถˆ๋ณ€์„ฑ

์–ธ๊ธ‰ํ–ˆ๋‹ค์‹œํ”ผ, readonly๋Š” ๊นŠ์€ ๋ถˆ๋ณ€์„ฑ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์จ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ts-essentials์—์„œ ์ œ๊ณตํ•˜๋Š” DeepReadonly๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž.

๋ถˆ๋ณ€์„ฑ์„ ์œ„ํ•œ ๊ฐ€์ด๋“œ

ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์˜ ๊ฐ์ฒด์— ๋ถˆ๋ณ€์„ฑ์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•˜๋ฏ€๋กœ, ํ”„๋กœ์ ํŠธ์˜ ํ•ต์‹ฌ ์•„ํ‚คํ…์ณ ์›๋ฆฌ์— ํ†ตํ•ฉ๋˜์–ด์•ผ ํ•œ๋‹ค. ๋ฌผ๋ก  ์†Œํ”„ํŠธ์›จ์–ด ์ „๋ฌธ๊ฐ€๋“ค์ด ์–ด๋А์ •๋„๊นŒ์ง€ ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ์ ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€๋Š” ๋งŽ์€ ๋…ผ์Ÿ์ด ์žˆ์—ˆ์ง€๋งŒ, ๋Œ€์ฒด๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์ง€์นจ์„ ์ถ”์ฒœํ•œ๋‹ค.

  • const๋กœ ๋ณ€์ˆ˜ ์„ ์–ธํ•˜๊ธฐ
  • ์ปดํŒŒ์ผ ํƒ€์ž… ๋ถˆ๋ณ€์„ฑ ์‚ฌ์šฉ
  • ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ ์‚ฌ์šฉ์„ ํ•จ์ˆ˜๋กœ๋งŒ ์ œํ•œ
  • Readonly<T>๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆ๋ณ€์˜ ํƒ€์ž…์œผ๋กœ ์„ ์–ธ
  • ๋ถˆ๋ณ€์˜ ์œ ํ˜•์—์„œ ์ ์ ˆํ•œ ์„œ๋ธŒํƒ€์ž…์„ ์ถ”์ถœํ•˜์—ฌ ๋ณ€์ด ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋˜, ์ด์— ๋Œ€ํ•œ ์‚ฌ์šฉ์„ ํ•œ์ • ์ง€์„ ๊ฒƒ
  • ์–•์€ ๋ถˆ๋ณ€์„ฑ์€ ๊นŠ์€ ๋ถˆ๋ณ€์„ฑ์„ ํšจ๊ณผ์ ์œผ๋กœ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ๊ฒƒ (= ์–•์€ ๋ถˆ๋ณ€์„ฑ ๋งŒ์œผ๋กœ ๊นŠ์€ ๋ถˆ๋ณ€์„ฑ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค)
  • ํ•จ์ˆ˜๋Š” ๋ถˆ๋ณ€์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.
  • ํ•จ์ˆ˜๋Š” ๋ถˆ๋ณ€๊ฐ’์„ ๋ฆฌํ„ดํ•ด์•ผ ํ•œ๋‹ค.
  • ๊ฐ€์žฅ ์ตœ์„ ์˜ ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•จ์ˆ˜๋‹ค.

ํ”„๋กœ์ ํŠธ ์ „์ฒด ์˜์—ญ์— ๋ถˆ๋ณ€ ํƒ€์ž…์„ ์„ ์–ธํ•˜๋ฉด, ๊ฐœ๋ฐœ์ž๋“ค์€ ๊ฐœ๋ฐœ์‹œ์— ๋ถˆ๋ณ€์„ฑ์„ ๋จผ์ € ์—ผ๋‘ํ•ด๋‘˜ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ๋ถˆ๋ณ€ํƒ€์ž…์˜ ๋„์›€์„ ์–ป์–ด ๋ณด๋‹ค ๋ณต์žกํ•œ ํƒ€์ž…์„ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์‹œ์Šคํ…œ์˜ ๋Œ€๋ถ€๋ถ„์˜ ํ•จ์ˆ˜๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ตฌ์กฐ๋ฅผ ์ˆ˜์šฉํ•˜๊ณ , ์ด๋ฅผ ๋งŒ๋“ค์–ด ๋‚ด์•ผ ํ•œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์ž.

type Writable<K extends string | number | symbol, V> = {
  -readonly [P in K]: V
}

type ExtractFromReadonlySet<T> = T extends ReadonlySet<infer R> ? R : never
type ExtractFromReadonlyArray<T> = T extends ReadonlyArray<infer R> ? R : never
type ExtractFromReadonlyMap<T> =
  T extends ReadonlyMap<infer K, infer V> ? [K, V] : never
// ์–•์€ ์ˆ˜์ค€์˜ ๋ถˆ๋ณ€์„ฑ ํƒ€์ž…์„ ์ด์šฉํ•˜์—ฌ, ๊นŠ์€ ๋ถˆ๋ณ€์„ฑ์„ ๊ฐ•์ œํ•œ๋‹ค.
type User = Readonly<{
  id: string
  groups: ReadonlySet<
    Readonly<{
      id: string
      public: boolean
    }>
  >
}>

// ReadonlySet๋กœ ๋ถ€ํ„ฐ ํƒ€์ž…์„ ์ถ”์ถœํ•œ๋‹ค.
type ExtractFromReadonlySet<T> = T extends ReadonlySet<infer R> ? R : never

// ํ•จ์ˆ˜๋Š” ๋ถˆ๋ณ€์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค
// ํ•จ์ˆ˜๊ฐ€ ๋ถˆ๋ณ€ ํƒ€์ž…์˜ ๊ฐ’์„ ๋ฆฌํ„ดํ•œ๋‹ค.
// ์ˆœ์ˆ˜ํ•จ์ˆ˜
const getUserPublicGroupIds = (user: User): User['groups'] => {
  // ๋ณ€์ˆ˜๋Š” const๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•œ๋‹ค.
  const set = new Set<ExtractFromReadonlySet<User['groups']>>()

  Array.from(user.groups).forEach((group) => {
    if (group.public) {
      set.add(group)
    }
  })

  return set
}

๋ฆฌํŒฉํ† ๋ง

์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ์—” ์ƒ๊ด€์—†์ง€๋งŒ, ์˜ค๋ž˜๋œ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋ฆฌํŒฉํ† ๋ง์€ ์ˆ™๋ จ๋œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋„ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์†Œํ”„ํŠธ์›จ์–ด ์ „๋ฌธ๊ฐ€๋“ค์ด ํ•ญ์ƒ ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์˜ ๋ณ€๊ฒฝ์„ ์‚ฌ์ „์— ๊ณ„ํšํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ์— ๋ถˆ๋ณ€์„ฑ์„ ๊ฐ•์ œํ•˜๋Š” ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด, ์•„๋ž˜์™€ ๊ฐ™์€ ๋ชฉ๋ก์„ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

  • ๊ธฐ์กด ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ๋ถˆ๋ณ€์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ๋ฌธ์ œ ํ•ด๊ฒฐ
  • ๊ธฐ์กด ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ถˆ๋ณ€์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ๋ฌธ์ œ ํ•ด๊ฒฐ
  • ์–•์€ ๋ณต์‚ฌ, ๋˜๋Š” ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ํ†ตํ•ด ๋ถˆ๋ณ€์˜ ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝ
  • ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ์ค‘์— ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž ์žฌ์ ์œผ๋กœ ๋ชจ๋“  ๋ฒ„๊ทธ๋ฅผ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€ํ•˜์ง€ ๋ง ๊ฒƒ
  • ๊ด‘๋ฒ”์œ„ํ•œ ํ…Œ์ŠคํŠธ์— ์˜์กด

๋ฆฌํ„ด ํƒ€์ž…์„ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋ฆฌํŒฉํ† ๋ง์˜ ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋ถˆ๋ณ€ํ•œ ๊ฐ’์œผ๋กœ ๋ฆฌํ„ดํ•˜๊ธฐ ์œ„ํ•ด, ์•„๋ž˜์™€ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

  • ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์–•์€ ๋ณต์‚ฌ๋ฅผ ํ•˜๊ฑฐ๋‚˜
  • ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ์ˆ˜์ •

๋ถˆ๋ณ€๊ฐ’์„ ์–•์€ ์ˆ˜์ค€์˜ ๋ถˆ๋ณ€๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ด๋ฏธ ์ •์˜๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฐ์ฒด: Object.assign({}, obj) {...obj}
  • ๋ฐฐ์—ด: arr.slice(), [...arr]

๋ฆฌํŒฉํ† ๋ง์ „

type User = {
  id: string
  groupIds: string[]
}

const mutableAppendGroupsToUser = (groupIds: string[], user: User): User => {
  user.groupIds = Array.from(new Set([...user.groupIds, ...groups]))

  return user
}

๋ฆฌํŒฉํ† ๋งํ›„

type ReadonlyUser = Readonly<{
  id: string
  groupIds: ReadonlyArray<string>
}>

// ์ด์ œ ํ•จ์ˆ˜๋Š” ์˜ค์ง ๋ถˆ๋ณ€ ํƒ€์ž…๋งŒ ๋ฐ›๋Š”๋‹ค.
const immutableAppendGroupsToUser = (
  groupIds: ReadonlyArray<string>,
  user: ReadonlyUser,
): ReadonlyUser => {
  // ๋” ์ด์ƒ `user.groupIds`๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  const newGroupIds = Array.from(new Set([...user.groupIds, ...groupIds]))

  // ํ•จ์ˆ˜๊ฐ€ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
  return Object.assign({}, user, {groupIds: newGroupIds})
}

๊ฐœ๋ฐœ์ž๋“ค์ด ํฐ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ํ•  ๋•Œ ์„ฑ๋Šฅ์ƒ์˜ ๋ฌธ์ œ๋ฅผ ์กฐ์‹ฌํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ ๋ถˆ๋ณ€์„ฑ์„ ๋„์ž…ํ•˜๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋„์›€์ด ์žˆ๋˜ ์—†๋˜ ๊ฐ„์— ์ด์ „๋ถ€ํ„ฐ ์žˆ์—ˆ๋˜ ๋ฒ„๊ทธ๊ฐ€ ์ˆ˜๋ฉด์œ„๋กœ ๋– ์˜ค๋ฅด๋Š” ์ผ์ด ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ํ”„๋กœ์ ํŠธ๋˜์ง€, ํ•ฉ๋ฆฌ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์ณ์•ผ๋งŒ ์ตœ์ข… ์‚ฌ์šฉ์ž์—๊ฒŒ ํ›Œ๋ฅญํ•œ ๊ฒฝํ—˜์„ ๋ณด์žฅํ•ด์ค€๋‹ค.

https://levelup.gitconnected.com/the-complete-guide-to-immutability-in-typescript-99154f859fdb