[TypeScript] 같은 key를 가진 객체 만들기

SeongMok Hong·2023년 9월 25일
0

개요

사이드 프로젝트를 하던 와중, 프로젝트에 빈번하게 사용되는 Form을 편하게 사용하기 위해 UseForm Custom Hook을 개발하고 있었다.

initialValue를 인자로 받아 Form과 양방향 바인딩 될 formData, 유효성 검사를 위한 isError, 그리고 다양한 Type의 Input들의 onChange를 핸들링 하기 위한 함수가 포함되어 있다.

문제점

유효성 검사를 위해 필요한 isError 는, 예를 들어 initialValue{ firstName: '', lastName: ''} 라는 객체가 들어왔을 때, 해당 객체와 같은 key를 가지고, value는 boolean Type인 객체를 { firstName: false, lastName: false } 와 같이 생성할 필요가 있었다.

그래서 처음엔 다음과 같이 Custom Hook을 작성하였다.

const makeSameKeyObj = (obj: any) => {
  const newObj = { ...obj };
  for (const key in newObj) {
    newObj[key] = false;
  }
  return newObj;
};

export const useForm = <T>(initialValue: T) => {
  const [formData, setFormData] = useState<T>(initialValue);

  const [isError, setIsError] = useState(makeSameKeyObj(initialValue));
  
  ...
}

이렇게 작성하니 작동은 잘 하였다!

다만 문제점은, makeSameKeyObj 함수의 인자 type이 any로 되어있어 자동완성이 안되고, 컴파일러가 에러를 잡지 못한다는 점 등 Typescript의 장점을 하나도 살리지 못하는 코드였다.

해결

makeSameKeyObj 함수를 Generic을 활용하여 작성하였다.
우선 인자로 같은 Key를 가진 객체, 그리고 초기값인 defaultValue 를 받는다.

const makeSameKeyObj = <T extends object, U>(obj: T, defaultValue: U) =>

이후 Reduce 함수를 통해 같은 Key를 가지고, 초기값은 defaultValue인 새로운 객체를 반환하도록 하였다. 초기값은 Record를 통해 타입 지정을 해주었다.

Object.keys(obj).reduce(
    (newObj, key) => ({
      ...newObj,
      [key]: defaultValue,
    }),
    {} as Record<keyof T, U>
  );

완성된 코드는 다음과 같다. 에디터를 통해 자동완성도 잘 되고, 에러도 잘 잡는 것을 확인하였다.

const makeSameKeyObj = <T extends object, U>(obj: T, defaultValue: U) =>
  Object.keys(obj).reduce(
    (newObj, key) => ({
      ...newObj,
      [key]: defaultValue,
    }),
    {} as Record<keyof T, U>
  );


export const useForm = <T extends object>(initialValue: T) => {
  const [formData, setFormData] = useState<T>(initialValue);

  const [isError, setIsError] = useState<Record<keyof T, boolean>>(
    makeSameKeyObj(initialValue, false)
  );

참고

https://stackoverflow.com/questions/56090662/typescript-create-object-with-same-keys-but-different-values

profile
안녕하세요. 홍성목입니다.

0개의 댓글