import { Controller, Control, FieldError } from 'react-hook-form';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from '@/shared/ui/select';
import { ErrorMessage } from '@/shared/ui/errorMessage';
import { cn } from '@/shared/lib/utils';
import { MeFormData } from '../model/type';
const TIER_OPTIONS = [
{ value: 'bronze', label: '브론즈' },
{ value: 'silver', label: '실버' },
{ value: 'gold', label: '골드' },
{ value: 'platinum', label: '플레티넘' },
{ value: 'diamond', label: '다이아몬드' },
{ value: 'ascendant', label: '초월자' },
{ value: 'immortal', label: '불멸' },
{ value: 'radiant', label: '레디언트' },
];
export type TierSelectProps = {
control: Control<MeFormData>;
name: 'tier';
disabled?: boolean;
error?: FieldError;
placeholder?: string;
className?: string;
};
export function TierSelect({
control,
name,
disabled,
error,
placeholder = '티어 선택',
className,
}: TierSelectProps) {
return (
//...생략
);
}
위는 내 기준코드이고 이 컴포넌트를 다른 폼에서 사용하려하니 타입이 고정되면 안되겠다 싶어 타입을 제너릭으로 변경하고자하였음 AI와 함께(AI 가)작업함 ㅋㅋ;; 그래서 그를 참고해서 학습한 점을 정리하고자 함
일단 FieldValues리액트 훅폼에서 폼의 모든 필드 타입을 의미
type MyForm = {name : string, age : number}
여기서 MyForm은 FieldValues의 한 종류임
즉, T extends FieldValues를 통해 "T는 react-hook-form에서 사용할 수 있는 폼타입이어야 한다"는 의미를 나타내주어야 control 같은 reactHookForm의 객체?(폼 전체를 관리하는 객체)의 타입이 안정적으로 정해짐
type MyForm = { name: string; age: number; tier: string }
type NameField = Path<MyForm> // "name" | "age" | "tier"
Path<T>는 T 타입 객체의 키(key) 중 하나를 의미FieldValues: react-hook-form에서 사용할 수 있는 폼 타입의 집합Path<T>: 폼 타입 T의 실제 필드명(키)만 허용아래는 수정한 코드(with AI)
import {
Controller,
Control,
FieldError,
FieldValues,
Path,
} from 'react-hook-form';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from '@/shared/ui/select';
import { ErrorMessage } from '@/shared/ui/errorMessage';
import { cn } from '@/shared/lib/utils';
const TIER_OPTIONS = [
{ value: 'bronze', label: '브론즈' },
{ value: 'silver', label: '실버' },
{ value: 'gold', label: '골드' },
{ value: 'platinum', label: '플레티넘' },
{ value: 'diamond', label: '다이아몬드' },
{ value: 'ascendant', label: '초월자' },
{ value: 'immortal', label: '불멸' },
{ value: 'radiant', label: '레디언트' },
];
export type TierSelectProps<T extends FieldValues> = {
control: Control<T>;
name: Path<T>;
disabled?: boolean;
error?: FieldError;
placeholder?: string;
isMessage?: boolean;
triggerClassName?: string;
className?: string;
};
export function TierSelect<T extends FieldValues>({
control,
name,
disabled,
error,
placeholder = '티어 선택',
isMessage = true,
triggerClassName,
className,
}: TierSelectProps<T>) {
return (
// ...생략
);
}
<TierSelect<UserListSectionFormData>
control={control}
name='tier'
placeholder='티어 선택'
triggerClassName='data-[placeholder]:text-white'
isMessage={false}
/>
<TierSelect<MeFormData>
control={control}
name='tier'
disabled={!isEdit}
error={errors.tier}
/>
// 실제 사용