🤔

入力フォームのコンポーネントを作ってOmitを理解する

2025/04/11に公開

Omitってなんだ?

  • OmitはTypescriptにあるユーティリティ型(型を操作するための型)
  • Omitは型から任意のプロパティを除外できる

使い方

 type Sample = Omit<任意の型, '除外したいプロパティ名'>

実際に使ってみた

まず、Omitをどんな時に使ったかなんですが、下のフォームをコンポーネント化する時に使いました。RHFShadcnUIを組み合わせてFormを作ると下のようなコードになると思うんですけどこれ4つとかになるとめっちゃだるくない?って感じました。

BeforeInputForm.tsx
 return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="name"
          render={({ field }) => (
            <FormItem>
              <FormLabel>名前</FormLabel>
              <FormControl>
                <Input placeholder="山田 太郎" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>メールアドレス</FormLabel>
              <FormControl>
                <Input placeholder="example@example.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <Button type="submit">送信</Button>
      </form>
    </Form>

で、上のコードをコンポーネント化したものがこの下のコードです。

InputFormComponent.tsx
import {
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import type { FieldValues } from 'react-hook-form'
import type { InputFormProps } from '../../-types/inputform'

export const InputForm = <T extends FieldValues>({
  name,
  control,
  label,
  ...inputProps
}: InputFormProps<T>) => {
  return (
    <FormField
      control={control}
      name={name}
      render={({ field }) => (
        <FormItem>
          <FormLabel>{label}</FormLabel>
          <FormControl>
            <Input
              {...inputProps}
              onChange={field.onChange}
              value={field.value}
              onBlur={field.onBlur}
              disabled={field.disabled}
              name={field.name}
              ref={field.ref}
            />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
  )
}

ここで使用しているInputFormPropsの型定義をするときにOmitを使用しました。
型定義は以下のコードで、Omitの部分を見るとHTMLInputElementnameプロパティを除外しています。なぜ、除外しているか?
それは、RHFからimportしているUseControllerPropsnameプロパティが重複してしまっているので、型エラーが起きていました。
なので、RHFのnameプロパティを優先するためにOmitを使用して除外しました。

inputform.d.ts
import { FieldValues, UseControllerProps } from "react-hook-form";
import { InputHTMLAttributes } from "react";

// 入力フォームの型定義
export interface InputFormProps<T extends FieldValues> 
    extends Omit<InputHTMLAttributes<HTMLInputElement>, 'name'>, 
    UseControllerProps<T> {
        label: string
    }

まとめ

こんな感じでこの型と型のプロパティ、オプショナルじゃないのになんか重複してる!?って時に使えばいいんだなってことが分かりました。

Discussion