react-hook-form 공통 컴포넌트 작성 시 type 제네릭 작성

정해준·2024년 10월 10일

react-hook-form

input 공통 컴포넌트 작성

처음에 input 공통 컴포넌트를 작성하면서 react-hook-form의 register를 넣을 때 type을 지정해야 하는데 처음에 작성할 때는 아래처럼 작성했습니다.

import type { UseFormRegister } from "react-hook-form";

export interface InputProps {
//...type 설정
  register: UseFormRegister<any>;
  
}

처음에는 위에처럼 any를 주고 작성하였습니다.

type을 any로 주고 작성했더니 eslint에러가 발생하였습니다.

에러해결 과정

unkown

그래서 처음에는 any 대신에 unkown을 넣어 해결할려고 했지만 unkown을 사용하면 FieldValues의 제약 조건을 만족하지 않는다는 에러가 밣생했습니다.

FieldValues

그래서 UseFormRegister의 제네릭으로 FieldValues를 사용하여 type문제는 해결하는 듯 싶었지만 커스텀 타입으로 지정된 register를 props로 집어넣게 되면 FieldValues와 type 불일치가 일어나 에러가 떴습니다.

제네릭 사용

제네릭을 사용하여 커스텀 타입을 집어넣을 수 있게 해결하려고 시도하게 되었습니다.

import type { UseFormRegister } from "react-hook-form";

export interface InputProps<T> {
  size?: "big" | "small";
  type?: "text" | "password";
  placeholder?: string;
  register: UseFormRegister<T>;  // 제네릭 T를 사용
}
import React from "react";
import { InputProps } from "@/types/commonProps";

const Input = <T,>({ size, type, placeholder, register }: InputProps<T>) => {
  const height =
    (size === "big" && "h-14 text-body/22px") ||
    (size === "small" && "h-10 text-body/18px") ||
    "h-10 text-body/18px";

  const inputType =
    (type === "text" && "text") ||
    (type === "password" && "password") ||
    "text";

  return (
    <input
      type={inputType}
      placeholder={placeholder || ""}
      className={`p-4 w-full ${height} border border-solid border-black rounded-lg focus:outline-none`}
      {...register("text" as keyof T)}  // 제네릭 T의 필드를 안전하게 사용
    />
  );
};

export default Input;

위처럼 제네릭을 활용하여 작성하여 커스텀 타입을 사용할 수 있게 작성하였습니다.

하지만 위의 코드로 했을 때 2가지의 에러가 더 생겼습니다.

  • 'keyof T' 형식의 인수는 'Path' 형식의 매개 변수에 할당될 수 없습니다
  • 'T' 형식이 'FieldValues' 제약 조건을 만족하지 않습니다

위의 2에러가 발생하였습니다.

그래서 2개의 에러를 해결하기 위해서 아래처럼 코드를 수정했습니다.

import type { UseFormRegister, FieldValues, Path } from "react-hook-form";

export interface InputProps<T extends FieldValues> {
size?: "big" | "small";
type?: "text" | "password";
placeholder?: string;
register: UseFormRegister<T>;
}
import React from "react";
import { InputProps } from "@/types/commonProps";

const Input = <T extends FieldValues>({ size, type, placeholder, register }: InputProps<T>) => {
const height =
  (size === "big" && "h-14 text-body/22px") ||
  (size === "small" && "h-10 text-body/18px") ||
  "h-10 text-body/18px";

const inputType =
  (type === "text" && "text") ||
  (type === "password" && "password") ||
  "text";

return (
  <input
    type={inputType}
    placeholder={placeholder || ""}
    className={`p-4 w-full ${height} border border-solid border-black rounded-lg focus:outline-none`}
    {...register("text" as Path<T>)} // Path<T> 사용
  />
);
};

export default Input;

위에 처럼 수정하여 제네릭을 사용하여 type을 수정하였습니다.
그래서 위의 컴포넌트를 사용할 때는

"use client";

import React from "react";

import Input from "@/components/common/Input";

import useSearchInputBox from "@/hooks/maple/useSearchInputBox";

import type { SearchBox } from "@/types/maple/inputForm";

const SearchInputBox = () => {
const { form, onSubmitSearchHandler } = useSearchInputBox();

return (
  <div className="flex flex-col justify-center items-center gap-3 w-full h-96">
    <p className="text-title/32px">게임 캐릭터 검색</p>
    <div className="w-[560px]">
      <form onSubmit={form.handleSubmit(onSubmitSearchHandler)}>
      //커스텀 타입을 집어넣어서 type을 지정
        <Input<SearchBox>
          size="big"
          placeholder="캐릭터를 입력해주세요."
          register={form.register}
          value="text"
        />
      </form>
    </div>
  </div>
);
};

export default SearchInputBox;

위 처럼 제네릭으로 타입을 지정하여 type any에 떴었던 에러를 해결했습니다.

0개의 댓글