Ch14 중첩된 데이터에 함수형 도구 사용하기

·

2 min read

update() - 객체 값 변경하기

  • incrementQuantity(item), incrementSize(item)... => incrementField(item, field)

  • incrementField(item, field), decrementField(item, field), doubleField(item, field)... => update(object, key, modifier)

    • 당연히 여기에서도 copy-on-write 활용

update() 활용해 중첩된 객체 값 변경하기

  • 재귀 활용
// 책에 있는 JS 코드를 TS/ES6+ 코드로 변환
function nestedUpdate<T = Record<string, unknown>, S = Record<string, unknown>>(
  originObject: T,
  keys: string[],
  modifier: <S>(targetObject: S) => S
): T {
  if (keys.length === 0) return modifier(originObject);

  const firstKey = keys[0];
  const restKeys = dropFirst(keys);
  return update(originObject, firstKey, (nestedObjectOfFirstKey) =>
    nestedUpdate(nestedObjectOfFirstKey, restKeys, modifier)
  );
}

keys에 들어갈 값들을 literal type으로 선언할 수 있을까?

깊이 중첩된 구조에서 주의할 점

기억해야할 것이 너무 많을 때는 추상화 벽을 사용하자

  • 중첩된 각 단계에서 기억해야할 새로운 데이터 구조가 있고, 각 구조에 어떤 키가 있는지 기억하기 어려움

  • ex. 블로그 12번째 글에서 글쓴이 이름을 대문자로 바꾸는 경우

    • AS-IS

      • 한번에 모든 걸 다 처리

      • nestedUpdate(blogCatogory, ['posts', '12', 'author', 'name'], capitalize)

    • TO-BE

      • 의미 있는 이름을 가진 함수들 만들기

      • 어떤 값이 어떤 키에 들어있는지 일일이 기억하지 않아도 되고, 각각의 동작을 기억하기 쉬워짐

        type BlogCategory = {
          /**  */
        };
        type Post = {
          /**  */
        };
        type User = {
          /**  */
        };

        function updatePostById(
          blogCategory: BlogCategory,
          id: string,
          modifyPost: (post: Post) => Post
        ) {
          return nestedUpdate(blogCategory, ['posts', id], modifyPost);
        }

        function updateAuthor(post: Post, modifyUser: (user: User) => User) {
          return update(post, 'author', modifyUser);
        }

        function capitalizeName(user: User) {
          return update(user, 'name', capitalize);
        }

        // 사용
        updatePostById(blogCategory, '12', (post) =>
          updateAuthor(post, capitalizeName)
        );