Immutable model in TS

곰튀김·2022년 8월 2일
0

immutable 모델 만들기

1. getter only class

class User {
  private _name: string;
  private _age: number;

  constructor(name: string, age: number) {
    this._name = name;
    this._age = age;
  }

  get name(): string {
    return this._name;
  }

  get age(): number {
    return this._age;
  }
}

const user = new User('곰튀김', 28);

필드 변수가 많아지만 점점 관리가 어려워짐. constuctor나 getter는 WebStorm 이 만들어주기는 하지만, 코드가 길어져서 불편.
생성할 때 전부 초기값을 넣어야 해서 불편.
Builder 패턴을 적용해보기도 하지만 모델이 많아지면 역시 귀찮음.

2. readonly type

interface User {
  readonly name: string;
  readonly age: number;
}

const user: User = {
  name: '곰튀김',
  age: 28,
};

타입 정의할 때 readonly로 정의해버림. set의 허용을 선택할 수 있음.
nested object 안에서도 각각 다 해줘야 함.

interface 나 type 이나 둘 다 똑같이 적용가능

type User = {
  readonly name: string;
  readonly age: number;
};

타입을 항상 미리 정의해 줘야 함.
type 이나 interface를 nested 영역에서 정의할 수 없음. 임시로 만들어지는 immutable 데이터에 대해서도 정의가 필요하고, export 해야할 경우가 많음.

3. as const

const user = {
  name: '곰튀김',
  age: 28,
} as const;

object 데이터 생성과 함께 const 로 얼려버림.
nested objet 안에서도 각각 다 지정 해줘야 함.
별도의 타입을 만들어주지 않아도 되니까 임시로 데이터를 만들어 전달할 때 유용함.
생성시에 지정되는 것으로 이미 만들어진 데이터에 대해서 적용할 수 없음.

4. freeze()

const user = {
  name: '곰튀김',
  age: 28,
};
Object.freeze(user);

이미 만들어진 object 를 immutable 하게 만들어줌.
nested 된 object 에는 적용되지 않음.

deepFreeze 같은 Util을 만들어서 전체 다 immutable 하게 만들 수 있음

deepFreeze.ts

const deepFreeze = (obj: any) => {
  Object.keys(obj).forEach((prop) => {
    if (typeof obj[prop] === "object" && !Object.isFrozen(obj[prop])) {
      deepFreeze(obj[prop]);
    }
  });
  return Object.freeze(obj);
};

(출처: 30-seconds-of-typescript)


그래도

이렇게 해봐도 compile time 에만 immutable이 유지될 뿐,
이미 js로 변환된 후 runtime 에서는 immutable이 유지되지 않더라.

profile
사실주의 프로그래머

0개의 댓글