◼️

Zodでスキーマオブジェクトを使い回す方法

2024/06/28に公開

こんにちは。中塚です。

はじめに

Zodは、TypeScriptのためのスキーマ宣言と検証のライブラリで、オブジェクトのバリデーションを簡単に行うことができます。この記事では、Zodを使用してスキーマオブジェクトを効率的に使い回す方法について説明します。今回は、動物園をテーマに例を作成し、動物データのスキーマを入力フォームとAPIで再利用する方法をご紹介いたします。

Zodの基本

まずは、基本的なZodの使い方をおさらいいたします。以下のコードでは、AnimalSchemaを定義しています。

import { z } from "zod";

const AnimalSchema = z.object({
  id: z.string(),
  name: z.string(),
  species: z.string(),
  age: z.number().nullable(),
  habitat: z.string(),
});

type Animal = z.infer<typeof AnimalSchema>;

このスキーマは、動物のID、名前、種、年齢、および生息地を表すフィールドを持っています。

スキーマオブジェクトの使い回し

同じスキーマを異なるコンテキストで使いたい場合、Zodのオブジェクトを再利用することができます。例えば、動物のデータを入力フォームとAPIの両方で使用したい場合、以下のように定義します。

// AnimalSchemaのキーをAPIのSchemaから取得
const animalKeys = getKeyMapping(AnimalSchema.shape);

// 入力フォーム用スキーマ
export const AnimalFormValuesSchema = z
  .object({
    [animalKeys.id]: z.string(),
    [animalKeys.name]: z.string(),
    [animalKeys.species]: z.string(),
    [animalKeys.age]: createNumberInputSchema({ defaultValue: null }),
    [animalKeys.habitat]: z.string(),
  });

getKeyMapping関数を使用することで、スキーマキーを動的に取得し、コードの一貫性と再利用性を高めることができます。

入力フォーム用スキーマの作成

入力フォームで使用するスキーマには、特定のバリデーションロジックやデフォルト値を設定する必要があります。以下のコードは、数値入力フィールドのスキーマを作成するためのヘルパー関数です。
(コードフォロー時にご教示いただきました。)

export const createNumberInputSchema = <T>({
  defaultValue,
  errorMessage = i18n.t('constants.common.FORM.INVALID_NUMBER'),
}: {
  defaultValue?: T;
  errorMessage?: string;
}) =>
  z.string().transform((value, ctx) => {
    const asNum = Number(toHalfWidth(value));
    if (value !== '' && Number.isNaN(asNum))
      ctx.addIssue({
        code: 'custom',
        message: errorMessage,
      });
    return value === '' ? defaultValue : asNum;
  });

入力欄が空の場合、NaNとなり厄介です。
この関数は、文字列として入力された値を数値に変換し、変換できない場合にはカスタムエラーメッセージを追加します。また、空文字の場合にはデフォルト値を返します。

スキーマのマージ

Zodを使用すると、スキーマオブジェクトをマージすることができ、異なるスキーマを統合して一貫性を持たせることが可能です。たとえば、以下のように既存のスキーマをマージして、新しいスキーマを作成できます。部分的にピックすることで、必要なフィールドだけを含むスキーマを簡単に作成できます。

// AnimalSchemaのキーを取得
const animalKeys = getKeyMapping(AnimalSchema.shape);

// 入力フォーム用スキーマ
export const AnimalFormValuesSchema = z
  .object({
    [animalKeys.age]: createNumberInputSchema({ defaultValue: null }),
  }).merge(AnimalSchema.pick({
    id: true,
    name: true,
    species: true,
    habitat: true,
  }));

このコードでは、AnimalSchemaのキーを動的に取得し、数値入力部分以外のフィールドをpickすることで、必要なフィールドだけを含むスキーマを作成しています。

まとめ

Zodを使うことで、スキーマオブジェクトを効率的に使い回すことができます。これにより、重複するコードを減らし、メンテナンス性を向上させることができます。

Aipictors

Discussion