Ch14 중첩된 데이터에 함수형 도구 사용하기
Table of contents
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)
);