ウェブサイト検索

typescript - Zod: 既存の型を使用してスキーマを作成する


私は、methodというパラメータを取得するエンドポイントを持っており、このパラメータはAxiosの型Methodに準拠している必要があります。

Zodで値がSchema型を使用していることを検証するスキーマをどのように作成できますか?

import { Method } from 'axios';

const Schema = zod.object({
  method: zod.someHowUseTheTypeFrom(Method),
});

Axios パッケージの Method の型は次の通りです:

export type Method =
  | 'get' | 'GET'
  | 'delete' | 'DELETE'
  | 'head' | 'HEAD'
  | 'options' | 'OPTIONS'
  | 'post' | 'POST'
  | 'put' | 'PUT'
  | 'patch' | 'PATCH'
  | 'purge' | 'PURGE'
  | 'link' | 'LINK'
  | 'unlink' | 'UNLINK'

回答 #1

あなたのコメントを読んでいると、axios の Method 型とスキーマが同期していることを確認したいように聞こえます。次のことを行うことをお勧めします:

import { z } from 'zod';
import type { Method } from 'axios';

const methods: z.ZodType<Method> = z.enum(['get', 'GET', ...]);

これにより少なくとも、式の右辺のスキーマが有効な axios Method の結果を解析することが強制されます。残念ながら、それ以上のことは、axios が Method 型の値に対応する文字列を含む配列もエクスポートしない限り、手の届かない可能性があります。

あなたが探していた元のもの z.something(<type here>) は機能しません。なぜなら、zod は実際のランタイムオブジェクトを使用しており、Method のような型はランタイムには存在しないからです。もし axios がメソッドを含む配列をエクスポートしていたなら、それはランタイムの値となり、(型キャストなどを使って)methods スキーマを生成するために使用できたでしょう。(この点については後ほど詳しく説明します。)

このアプローチのもう一つの欠点は、次のようなものでも型チェックされることです:

const methods z.ZodType<Method> = z.enum(['get']);

その理由は、TypeScript における型の働き方にあります。その enum スキーマは 'get' に対してのみ正常に解析されますが、リテラル 'get' は Method で定義されたより大きな合併型のサブタイプであるため、生成されたスキーマも割り当て可能です。

次に提案するオプションは、Method 内のすべての値を再宣言する必要があるため、やや自己矛盾しているように感じるかもしれません。しかし、axios の Method タイプを引き続き使用でき、Method 内のすべての値を解析するスキーマを確実に持つことができます(つまり、前述の問題に陥ることはありません)。

import { z } from "zod";
import { Method } from "axios";

const METHOD_MAP: { [K in Method]: null } = {
  get: null,
  GET: null,
  delete: null,
  DELETE: null,
  head: null,
  HEAD: null,
  options: null,
  OPTIONS: null,
  post: null,
  POST: null,
  put: null,
  PUT: null,
  patch: null,
  PATCH: null,
  purge: null,
  PURGE: null,
  link: null,
  LINK: null,
  unlink: null,
  UNLINK: null
};

const METHODS = (Object.keys(METHOD_MAP) as unknown) as readonly [
  Method,
  ...Method[]
];
const methods: z.ZodType<Method> = z.enum(METHODS);

ここでの METHODS に対する型アサーションは安全です。なぜなら、METHODS_MAP はエクスポートされておらず、そのキーが正確に何であるかを知っているからです。ただし、METHOD_MAP オブジェクトは、もし Method の値が欠けている場合に型エラーを引き起こすため、結果として得られるスキーマはすべての Method の値をコンパイル時に保証された形で解析します。

回答 #2

私は、z.custom<ExistingType>() を使用することが自分にはうまくいくことを見つけ、この種の問題に適していることが分かりました。

[編集済み] @esteban-toress によると、最後に次のようなバリデーション関数を追加する必要があります:z.custom<ExistingType>((value) => //何かをして & ブール値を返す)。そうしないと、単に z.custom<ExistingType>() は ZodAny 型を返すだけで、any 値を許可してしまいます。

[編集済み] この解決策は、TypeScriptの型を満たすために使用したい場合にのみ、型推論には好ましいですが、上記の動作のため、Zodのバリデーションにはお勧めしません。

ドキュメントを参照: https://zod.dev/?id=custom-schemas

関連記事