Zenn
☃️

スキーマライブラリの共通インターフェイスを提供するstandard-schema v1をご紹介

2025/01/28に公開

standard-schemaのv1がリリースされたので触ってみた。

https://github.com/standard-schema/standard-schema

standard-schema とは

現在バリデーションライブラリとしてzodvalibotarktypeなどがありますが、それらをTanStack Formなどの別ライブラリと統合して使用する際には専用のadapterを使用する必要がありました。以下のコードはTanStack Formとzodを組み合わせた時の例です。

import { useForm } from "@tanstack/react-form";
// zod用のadapterをインストールする必要がある
import { zodValidator } from "@tanstack/zod-form-adapter";
import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
});

export function Form() {
  const form = useForm({
    defaultValues: {
      name: "",
    },
    // zodValidatorをセットする
    validatorAdapter: zodValidator(),
    validators: {
      onChange: userSchema,
    },
    onSubmit: (values) => {
      console.log(values);
    },
  });

  return (
    <form onSubmit={form.handleSubmit}>
      <form.Field
        name="name"
        children={(field) => (
          <div>
            <label htmlFor={field.name}>Name:</label>
            <input
              id={field.name}
              name={field.name}
              value={field.state.value}
              onBlur={field.handleBlur}
              onChange={(e) => field.handleChange(e.target.value)}
            />
          </div>
        )}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

また、TanStack Formではこのadapterがzod、yup、valibotのものしかなく、それ以外のバリデーションライブラリと組み合わせることはできませんでした(後述しますが、最新のTanStack Formはstandard-schemaを受け入れているため、他のライブラリも使えます)。

しかしなぜ、各バリデーションライブラリ専用のadapterが必要なのでしょうか。それは各ライブラリごとにinterfaceが違うからです。そこで登場したのがstandard-schemaです。

standard-schemaはバリデーションライブラリの共通インターフェースを定義し、その定義に沿って各バリデーションライブラリが実装することにより、ライブラリに互換性を持たせ、1つのadapterでさまざまなバリデーションライブラリを使用できるようにすることを目的としています。

standard-schemaの使い方

READMEにも書かれているシンプルな使い方を紹介します。まず、standardValidateという関数を定義します。

https://github.com/apple-yagi/standard-schema-demo/blob/main/src/lib/standard-validate.ts

次にstandard-schemaのインターフェースを実装しているライブラリでスキーマを定義します。

https://github.com/apple-yagi/standard-schema-demo/blob/main/src/schema/string.ts

そして、standardValidateとスキーマを組み合わせ、以下のonSubmit関数の中で行なっているようにバリデーションを実行することができます。

https://github.com/apple-yagi/standard-schema-demo/blob/main/src/App.tsx

standardValidateの第2引数にはstandard-schemaのインターフェースを実装しているライブラリであれば、どのライブラリでも使用できるため、ライブラリの差し替えが容易になります。

各ライブラリの対応

standard-schemaを実装しているバリデーションライブラリと、standard-schemaをサポートしているライブラリは以下に記載されています。

https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec

TanStack Form

初めの方でTanStack Formとzodの組み合わせの例を紹介しましたが、TanStack Formもstandard-schemaをサポートしており、現在の最新のバージョンでは@tanstack/zod-form-adapterのようなライブラリを使用する必要はなくなりました。また、組み合わせることのできるバリデーションライブラリもstandard-schemaを実装しているバリデーションライブラリであれば自由に選べるようになりました。

以下がstandard-schemaを利用したときの例です。差分としては@tanstack/zod-form-adapterを削除しただけです。

import { useForm } from "@tanstack/react-form";
- // zod用のadapterをインストールする必要がある
- import { zodValidator } from "@tanstack/zod-form-adapter";
import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
});

export function Form() {
  const form = useForm({
    defaultValues: {
      name: "",
    },
-    // zodValidatorをセットする
-    validatorAdapter: zodValidator(),
    validators: {
      onChange: userSchema,
    },
    onSubmit: (values) => {
      console.log(values);
    },
  });

  return (
    <form onSubmit={form.handleSubmit}>
      <form.Field
        name="name"
        children={(field) => (
          <div>
            <label htmlFor={field.name}>Name:</label>
            <input
              id={field.name}
              name={field.name}
              value={field.state.value}
              onBlur={field.handleBlur}
              onChange={(e) => field.handleChange(e.target.value)}
            />
          </div>
        )}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

これにより、standard-schemaをサポートする前のTanStack Formではzod、valibot、yupしか選べませんでしたが、サポート後はArkType、Arri Schema、TypeMapも使えるようになりました。今後もstandard-schemaを実装するバリデーションライブラリが増えれば、さらに色々なバリデーションライブラリを使えるようになるでしょう。

まとめ

standard-schemaの登場により、adapterのようなglueなライブラリが必要なくなり、ライブラリの組み合わせの自由度が増しました。今後、standard-schemaを実装/サポートするライブラリが増えることでバリデーションライブラリの乗り換えなども楽になりそうだなと思っており、楽しみです。

Discussion

ログインするとコメントできます