💎 Zod 4 is now stable!  Read the announcement.
Zod logo

スキーマの定義

データを検証するには、まず スキーマ を定義する必要があります。スキーマは、単純なプリミティブ値から複雑なネストされたオブジェクトや配列まで、 を表します。

プリミティブ (Primitives)

import * as z from "zod";
 
// primitive types
z.string();
z.number();
z.bigint();
z.boolean();
z.symbol();
z.undefined();
z.null();

Coercion (強制型変換)

入力データを適切な型に強制変換するには、代わりに z.coerce を使用します:

z.coerce.string();    // String(input)
z.coerce.number();    // Number(input)
z.coerce.boolean();   // Boolean(input)
z.coerce.bigint();    // BigInt(input)

これらのスキーマの強制変換バリアントは、入力値を適切な型に変換しようとします。

const schema = z.coerce.string();
 
schema.parse("tuna");    // => "tuna"
schema.parse(42);        // => "42"
schema.parse(true);      // => "true"
schema.parse(null);      // => "null"

これらの強制変換スキーマの入力型はデフォルトで unknown です。より具体的な入力型を指定するには、ジェネリックパラメータを渡します:

const A = z.coerce.number();
type AInput = z.input<typeof A>; // => unknown
 
const B = z.coerce.number<number>();
type BInput = z.input<typeof B>; // => number

リテラル (Literals)

リテラルスキーマは、 "hello world"5 のような リテラル型 を表します。

const tuna = z.literal("tuna");
const twelve = z.literal(12);
const twobig = z.literal(2n);
const tru = z.literal(true);

JavaScriptのリテラル nullundefined を表すには:

z.null();
z.undefined();
z.void(); // equivalent to z.undefined()

複数のリテラル値を許可するには:

const colors = z.literal(["red", "green", "blue"]);
 
colors.parse("green"); // ✅
colors.parse("yellow"); // ❌

リテラルスキーマから許可された値のセットを抽出するには:

colors.values; // => Set<"red" | "green" | "blue">

文字列 (Strings)

Zodは、組み込みの文字列検証および変換APIをいくつか提供しています。一般的な文字列検証を実行するには:

z.string().max(5);
z.string().min(5);
z.string().length(5);
z.string().regex(/^[a-z]+$/);
z.string().startsWith("aaa");
z.string().endsWith("zzz");
z.string().includes("---");
z.string().uppercase();
z.string().lowercase();

単純な文字列変換を実行するには:

z.string().trim(); // trim whitespace
z.string().toLowerCase(); // toLowerCase
z.string().toUpperCase(); // toUpperCase
z.string().normalize(); // normalize unicode characters

文字列フォーマット (String formats)

一般的な文字列フォーマットに対して検証するには:

z.email();
z.uuid();
z.url();
z.httpUrl();       // http or https URLs only
z.hostname();
z.emoji();         // validates a single emoji character
z.base64();
z.base64url();
z.hex();
z.jwt();
z.nanoid();
z.cuid();
z.cuid2();
z.ulid();
z.ipv4();
z.ipv6();
z.mac();
z.cidrv4();        // ipv4 CIDR block
z.cidrv6();        // ipv6 CIDR block
z.hash("sha256");  // or "sha1", "sha384", "sha512", "md5"
z.iso.date();
z.iso.time();
z.iso.datetime();
z.iso.duration();

メールアドレス (Emails)

メールアドレスを検証するには:

z.email();

デフォルトでは、Zodは一般的な文字を含む通常のメールアドレスを検証するように設計された、比較的厳密なメール正規表現を使用します。これはGmailによって強制されるルールと概ね同等です。この正規表現の詳細については、 この投稿 を参照してください。

/^(?!\.)(?!.*\.\.)([a-z0-9_'+\-\.]*)[a-z0-9_+-]@([a-z0-9][a-z0-9\-]*\.)+[a-z]{2,}$/i

メール検証の動作をカスタマイズするには、 pattern パラメータにカスタム正規表現を渡すことができます。

z.email({ pattern: /your regex here/ });

Zodは、使用できるいくつかの便利な正規表現をエクスポートしています。

// Zod's default email regex
z.email();
z.email({ pattern: z.regexes.email }); // equivalent
 
// the regex used by browsers to validate input[type=email] fields
// https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/email
z.email({ pattern: z.regexes.html5Email });
 
// the classic emailregex.com regex (RFC 5322)
z.email({ pattern: z.regexes.rfc5322Email });
 
// a loose regex that allows Unicode (good for intl emails)
z.email({ pattern: z.regexes.unicodeEmail });

UUID

UUIDを検証するには:

z.uuid();

特定のUUIDバージョンを指定するには:

// supports "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"
z.uuid({ version: "v4" });
 
// for convenience
z.uuidv4();
z.uuidv6();
z.uuidv7();

RFC 9562/4122 UUID仕様では、バイト8の最初の2ビットが 10 であることが要求されます。他のUUID風の識別子はこの制約を強制しません。任意のUUID風の識別子を検証するには:

z.guid();

URL

WHATWG互換のURLを検証するには:

const schema = z.url();
 
schema.parse("https://example.com"); // ✅
schema.parse("http://localhost"); // ✅
schema.parse("mailto:[email protected]"); // ✅

ご覧のとおり、これは非常に寛容です。内部的には new URL() コンストラクタを使用して入力を検証します。この動作はプラットフォームやランタイムによって異なる場合がありますが、特定のJSランタイム/エンジンでURI/URLを検証する最も厳密な方法です。

ホスト名を特定の正規表現に対して検証するには:

const schema = z.url({ hostname: /^example\.com$/ });
 
schema.parse("https://example.com"); // ✅
schema.parse("https://zombo.com"); // ❌

プロトコルを特定の正規表現に対して検証するには、 protocol パラメータを使用します。

const schema = z.url({ protocol: /^https$/ });
 
schema.parse("https://example.com"); // ✅
schema.parse("http://example.com"); // ❌

Web URL — 多くの場合、Web URLを具体的に検証したいでしょう。推奨されるスキーマは次のとおりです:

const httpUrl = z.url({
  protocol: /^https?$/,
  hostname: z.regexes.domain
});

このプロトコルを http/https に制限し、ホスト名が z.regexes.domain 正規表現を使用した有効なドメイン名であることを確認します:

/^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/

URLを正規化するには、 normalize フラグを使用します。これにより、入力値が new URL() によって返される 正規化されたURL で上書きされます。

new URL("HTTP://ExAmPle.com:80/./a/../b?X=1#f oo").href
// => "http://example.com/b?X=1#f%20oo"

ISO 日時 (ISO datetimes)

お気づきかもしれませんが、Zodの文字列にはいくつか日付/時刻関連のバリデーションが含まれています。これらのバリデーションは正規表現に基づいているため、完全な日付/時刻ライブラリほど厳密ではありません。しかし、ユーザー入力を検証するには非常に便利です。

z.iso.datetime() メソッドは ISO 8601 を強制します。デフォルトでは、タイムゾーンオフセットは許可されません:

const datetime = z.iso.datetime();
 
datetime.parse("2020-01-01T06:15:00Z"); // ✅
datetime.parse("2020-01-01T06:15:00.123Z"); // ✅
datetime.parse("2020-01-01T06:15:00.123456Z"); // ✅ (arbitrary precision)
datetime.parse("2020-01-01T06:15:00+02:00"); // ❌ (offsets not allowed)
datetime.parse("2020-01-01T06:15:00"); // ❌ (local not allowed)

タイムゾーンオフセットを許可するには:

const datetime = z.iso.datetime({ offset: true });
 
// allows timezone offsets
datetime.parse("2020-01-01T06:15:00+02:00"); // ✅
 
// basic offsets not allowed
datetime.parse("2020-01-01T06:15:00+02");    // ❌
datetime.parse("2020-01-01T06:15:00+0200");  // ❌
 
// Z is still supported
datetime.parse("2020-01-01T06:15:00Z"); // ✅ 

修飾されていない(タイムゾーンなしの)日時を許可するには:

const schema = z.iso.datetime({ local: true });
schema.parse("2020-01-01T06:15:01"); // ✅
schema.parse("2020-01-01T06:15"); // ✅ seconds optional

許容される時間の precision(精度)を制限するには。デフォルトでは、秒は省略可能で、任意のサブ秒精度が許可されます。

const a = z.iso.datetime();
a.parse("2020-01-01T06:15Z"); // ✅
a.parse("2020-01-01T06:15:00Z"); // ✅
a.parse("2020-01-01T06:15:00.123Z"); // ✅
 
const b = z.iso.datetime({ precision: -1 }); // minute precision (no seconds)
b.parse("2020-01-01T06:15Z"); // ✅
b.parse("2020-01-01T06:15:00Z"); // ❌
b.parse("2020-01-01T06:15:00.123Z"); // ❌
 
const c = z.iso.datetime({ precision: 0 }); // second precision only
c.parse("2020-01-01T06:15Z"); // ❌
c.parse("2020-01-01T06:15:00Z"); // ✅
c.parse("2020-01-01T06:15:00.123Z"); // ❌
 
const d = z.iso.datetime({ precision: 3 }); // millisecond precision only
d.parse("2020-01-01T06:15Z"); // ❌
d.parse("2020-01-01T06:15:00Z"); // ❌
d.parse("2020-01-01T06:15:00.123Z"); // ✅

ISO 日付 (ISO dates)

z.iso.date() メソッドは、 YYYY-MM-DD 形式の文字列を検証します。

const date = z.iso.date();
 
date.parse("2020-01-01"); // ✅
date.parse("2020-1-1"); // ❌
date.parse("2020-01-32"); // ❌

ISO 時刻 (ISO times)

z.iso.time() メソッドは、 HH:MM[:SS[.s+]] 形式の文字列を検証します。デフォルトでは、秒は省略可能であり、サブ秒の小数も同様です。

const time = z.iso.time();
 
time.parse("03:15"); // ✅
time.parse("03:15:00"); // ✅
time.parse("03:15:00.9999999"); // ✅ (arbitrary precision)

いかなる種類のオフセットも許可されません。

time.parse("03:15:00Z"); // ❌ (no `Z` allowed)
time.parse("03:15:00+02:00"); // ❌ (no offsets allowed)

precision パラメータを使用して、許容される小数精度を制限します。

z.iso.time({ precision: -1 }); // HH:MM (minute precision)
z.iso.time({ precision: 0 });  // HH:MM:SS (second precision)
z.iso.time({ precision: 1 });  // HH:MM:SS.s (decisecond precision)
z.iso.time({ precision: 2 });  // HH:MM:SS.ss (centisecond precision)
z.iso.time({ precision: 3 });  // HH:MM:SS.sss (millisecond precision)

IPアドレス (IP addresses)

const ipv4 = z.ipv4();
ipv4.parse("192.168.0.0"); // ✅
 
const ipv6 = z.ipv6();
ipv6.parse("2001:db8:85a3::8a2e:370:7334"); // ✅

IPブロック (CIDR) (IP blocks (CIDR))

CIDR表記 で指定されたIPアドレス範囲を検証します。

const cidrv4 = z.cidrv4();
cidrv4.parse("192.168.0.0/24"); // ✅
 
const cidrv6 = z.cidrv6();
cidrv6.parse("2001:db8::/32"); // ✅

MACアドレス (MAC Addresses)

標準の48ビットMACアドレス IEEE 802 を検証します。

const mac = z.mac(); 
mac.parse("00:1A:2B:3C:4D:5E");  // ✅
mac.parse("00-1a-2b-3c-4d-5e");  // ❌ colon-delimited by default
mac.parse("001A:2B3C:4D5E");     // ❌ standard formats only
mac.parse("00:1A:2b:3C:4d:5E");  // ❌ no mixed case
 
// custom delimiter
const dashMac = z.mac({ delimiter: "-" });
dashMac.parse("00-1A-2B-3C-4D-5E"); // ✅

JWT (JWTs)

JSON Web Tokens を検証します。

z.jwt();
z.jwt({ alg: "HS256" });

ハッシュ (Hashes)

暗号化ハッシュ値を検証するには:

z.hash("md5");
z.hash("sha1");
z.hash("sha256");
z.hash("sha384");
z.hash("sha512");

デフォルトでは、 z.hash() は慣習どおり16進数エンコーディングを期待します。 enc パラメータを使用して別のエンコーディングを指定できます:

z.hash("sha256", { enc: "hex" });       // default
z.hash("sha256", { enc: "base64" });    // base64 encoding
z.hash("sha256", { enc: "base64url" }); // base64url encoding (no padding)

カスタムフォーマット (Custom formats)

独自の文字列フォーマットを定義するには:

const coolId = z.stringFormat("cool-id", ()=>{
  // arbitrary validation here
  return val.length === 100 && val.startsWith("cool-");
});
 
// a regex is also accepted
z.stringFormat("cool-id", /^cool-[a-z0-9]{95}$/);

このスキーマは "invalid_format" の問題を生成します。これは、refinements や z.custom() によって生成される "custom" エラーよりも説明的です。

myFormat.parse("invalid input!");
// ZodError: [
//   {
//     "code": "invalid_format",
//     "format": "cool-id",
//     "path": [],
//     "message": "Invalid cool-id"
//   }
// ]

テンプレートリテラル (Template literals)

新機能[email protected] で導入されました。

テンプレートリテラルスキーマを定義するには:

const schema = z.templateLiteral([ "hello, ", z.string(), "!" ]);
// `hello, ${string}!`

z.templateLiteral API は、任意の数の文字列リテラル(例: "hello")とスキーマを処理できます。推論された型が string | number | bigint | boolean | null | undefined に割り当て可能なスキーマであれば、どれでも渡すことができます。

z.templateLiteral([ "hi there" ]);
// `hi there`
 
z.templateLiteral([ "email: ", z.string() ]);
// `email: ${string}`
 
z.templateLiteral([ "high", z.literal(5) ]);
// `high5`
 
z.templateLiteral([ z.nullable(z.literal("grassy")) ]);
// `grassy` | `null`
 
z.templateLiteral([ z.number(), z.enum(["px", "em", "rem"]) ]);
// `${number}px` | `${number}em` | `${number}rem`

数値 (Numbers)

数値を検証するには z.number() を使用します。これは有限の数値を許可します。

const schema = z.number();
 
schema.parse(3.14);      // ✅
schema.parse(NaN);       // ❌
schema.parse(Infinity);  // ❌

Zodは、数値固有のバリデーションをいくつか実装しています:

z.number().gt(5);
z.number().gte(5);                     // alias .min(5)
z.number().lt(5);
z.number().lte(5);                     // alias .max(5)
z.number().positive();       
z.number().nonnegative();    
z.number().negative(); 
z.number().nonpositive(); 
z.number().multipleOf(5);              // alias .step(5)

(何らかの理由で) NaN を検証したい場合は、 z.nan() を使用します。

z.nan().parse(NaN);              // ✅
z.nan().parse("anything else");  // ❌

整数 (Integers)

整数を検証するには:

z.int();     // restricts to safe integer range
z.int32();   // restrict to int32 range

BigInt (BigInts)

BigIntを検証するには:

z.bigint();

Zodには、BigInt固有のバリデーションがいくつか含まれています。

z.bigint().gt(5n);
z.bigint().gte(5n);                    // alias `.min(5n)`
z.bigint().lt(5n);
z.bigint().lte(5n);                    // alias `.max(5n)`
z.bigint().positive(); 
z.bigint().nonnegative(); 
z.bigint().negative(); 
z.bigint().nonpositive(); 
z.bigint().multipleOf(5n);             // alias `.step(5n)`

ブール値 (Booleans)

ブール値を検証するには:

z.boolean().parse(true); // => true
z.boolean().parse(false); // => false

日付 (Dates)

Date インスタンスを検証するには z.date() を使用します。

z.date().safeParse(new Date()); // success: true
z.date().safeParse("2022-01-12T06:15:00.000Z"); // success: false

エラーメッセージをカスタマイズするには:

z.date({
  error: issue => issue.input === undefined ? "Required" : "Invalid date"
});

Zodは、日付固有のバリデーションをいくつか提供しています。

z.date().min(new Date("1900-01-01"), { error: "Too old!" });
z.date().max(new Date(), { error: "Too young!" });

列挙型 (Enums)

許容される 文字列 値の固定セットに対して入力を検証するには z.enum を使用します。

const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
 
FishEnum.parse("Salmon"); // => "Salmon"
FishEnum.parse("Swordfish"); // => ❌

注意 — 文字列配列を変数として宣言すると、Zodは各要素の正確な値を適切に推論できなくなります。

const fish = ["Salmon", "Tuna", "Trout"];
 
const FishEnum = z.enum(fish);
type FishEnum = z.infer<typeof FishEnum>; // string

これを修正するには、常に配列を直接 z.enum() 関数に渡すか、 as const を使用してください。

const fish = ["Salmon", "Tuna", "Trout"] as const;
 
const FishEnum = z.enum(fish);
type FishEnum = z.infer<typeof FishEnum>; // "Salmon" | "Tuna" | "Trout"

Enumのようなオブジェクトリテラル({ [key: string]: string | number })もサポートされています。

const Fish = {
  Salmon: 0,
  Tuna: 1
} as const
 
const FishEnum = z.enum(Fish)
FishEnum.parse(Fish.Salmon); // => ✅
FishEnum.parse(0); // => ✅
FishEnum.parse(2); // => ❌

外部で宣言されたTypeScriptのenumを渡すこともできます。

enum Fish {
  Salmon = 0,
  Tuna = 1
}
 
const FishEnum = z.enum(Fish);
FishEnum.parse(Fish.Salmon); // => ✅
FishEnum.parse(0); // => ✅
FishEnum.parse(2); // => ❌

Zod 4 — これはZod 3の z.nativeEnum() APIを置き換えるものです。

TypeScriptの enum キーワードを使用することは 推奨されていません

enum Fish {
  Salmon = "Salmon",
  Tuna = "Tuna",
  Trout = "Trout",
}
 
const FishEnum = z.enum(Fish);

.enum

スキーマの値をenumのようなオブジェクトとして抽出するには:

const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
 
FishEnum.enum;
// => { Salmon: "Salmon", Tuna: "Tuna", Trout: "Trout" }

.exclude()

特定の値を除外した新しいenumスキーマを作成するには:

const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);

.extract()

特定の値を抽出した新しいenumスキーマを作成するには:

const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
const SalmonAndTroutOnly = FishEnum.extract(["Salmon", "Trout"]);

ブール文字列 (Stringbools)

💎 Zod 4の新機能

場合によっては(例:環境変数の解析)、特定の文字列の「ブール値のような」値をプレーンな boolean 値に解析することが有益です。これをサポートするために、Zod 4では z.stringbool() が導入されました。

const strbool = z.stringbool();
 
strbool.parse("true")         // => true
strbool.parse("1")            // => true
strbool.parse("yes")          // => true
strbool.parse("on")           // => true
strbool.parse("y")            // => true
strbool.parse("enabled")      // => true
 
strbool.parse("false");       // => false
strbool.parse("0");           // => false
strbool.parse("no");          // => false
strbool.parse("off");         // => false
strbool.parse("n");           // => false
strbool.parse("disabled");    // => false
 
strbool.parse(/* anything else */); // ZodError<[{ code: "invalid_value" }]>

truthy(真)とfalsy(偽)の値をカスタマイズするには:

// these are the defaults
z.stringbool({
  truthy: ["true", "1", "yes", "on", "y", "enabled"],
  falsy: ["false", "0", "no", "off", "n", "disabled"],
});

デフォルトでは、スキーマは大文字と小文字を区別しません。すべての入力は truthy/falsy 値と比較される前に小文字に変換されます。大文字と小文字を区別するようにするには:

z.stringbool({
  case: "sensitive"
});

オプショナル (Optionals)

スキーマをオプショナルにする(つまり、 undefined 入力を許可する)には。

z.optional(z.literal("yoda")); // or z.literal("yoda").optional()

これは元のスキーマをラップする ZodOptional インスタンスを返します。内部スキーマを抽出するには:

optionalYoda.unwrap(); // ZodLiteral<"yoda">

ヌーラブル (Nullables)

スキーマをヌーラブルにする(つまり、 null 入力を許可する)には。

z.nullable(z.literal("yoda")); // or z.literal("yoda").nullable()

これは元のスキーマをラップする ZodNullable インスタンスを返します。内部スキーマを抽出するには:

nullableYoda.unwrap(); // ZodLiteral<"yoda">

Nullish

スキーマをnullishにする(オプショナルかつヌーラブル)には:

const nullishYoda = z.nullish(z.literal("yoda"));

nullish の概念の詳細については、TypeScriptのマニュアルを参照してください。

Unknown

ZodはTypeScriptの型システムを1対1で反映することを目指しています。そのため、Zodは以下の特別な型を表すAPIを提供しています:

// allows any values
z.any(); // inferred type: `any`
z.unknown(); // inferred type: `unknown`

Never

値はバリデーションを通過しません。

z.never(); // inferred type: `never`

オブジェクト (Objects)

オブジェクト型を定義するには:

  // all properties are required by default
  const Person = z.object({
    name: z.string(),
    age: z.number(),
  });
 
  type Person = z.infer<typeof Person>;
  // => { name: string; age: number; }

デフォルトでは、すべてのプロパティが必須です。特定のプロパティをオプショナルにするには:

const Dog = z.object({
  name: z.string(),
  age: z.number().optional(),
});
 
Dog.parse({ name: "Yeller" }); // ✅

デフォルトでは、認識されないキーは解析結果から削除されます:

Dog.parse({ name: "Yeller", extraKey: true });
// => { name: "Yeller" }

z.strictObject

未知のキーが見つかった場合にエラーをスローする*厳密な(strict)*スキーマを定義するには:

const StrictDog = z.strictObject({
  name: z.string(),
});
 
StrictDog.parse({ name: "Yeller", extraKey: true });
// ❌ throws

z.looseObject

未知のキーの通過を許可する*ルーズな(loose)*スキーマを定義するには:

const LooseDog = z.looseObject({
  name: z.string(),
});
 
LooseDog.parse({ name: "Yeller", extraKey: true });
// => { name: "Yeller", extraKey: true }

.catchall()

認識されないキーを検証するために使用されるcatchallスキーマを定義するには:

const DogWithStrings = z.object({
  name: z.string(),
  age: z.number().optional(),
}).catchall(z.string());
 
DogWithStrings.parse({ name: "Yeller", extraKey: "extraValue" }); // ✅
DogWithStrings.parse({ name: "Yeller", extraKey: 42 }); // ❌

.shape

内部スキーマにアクセスするには:

Dog.shape.name; // => string schema
Dog.shape.age; // => number schema

.keyof()

オブジェクトスキーマのキーから ZodEnum スキーマを作成するには:

const keySchema = Dog.keyof();
// => ZodEnum<["name", "age"]>

.extend()

オブジェクトスキーマに追加フィールドを加えるには:

const DogWithBreed = Dog.extend({
  breed: z.string(),
});

このAPIは既存のフィールドを上書きするために使用できます!この力には注意してください!2つのスキーマがキーを共有している場合、BがAを上書きします。

代替案: スプレッド構文 (spread syntax).extend() を完全に避けて、新しいオブジェクトスキーマをゼロから作成することもできます。これにより、結果のスキーマの厳密性レベルが視覚的に明らかになります。

const DogWithBreed = z.object({ // or z.strictObject() or z.looseObject()...
  ...Dog.shape,
  breed: z.string(),
});

これを使用して、複数のオブジェクトを一度にマージすることもできます。

const DogWithBreed = z.object({
  ...Animal.shape,
  ...Pet.shape,
  breed: z.string(),
});

このアプローチにはいくつかの利点があります:

  1. ライブラリ固有のAPIではなく、言語レベルの機能(スプレッド構文)を使用します
  2. 同じ構文がZodとZod Miniで機能します
  3. tsc 効率が良いです — .extend() メソッドは大きなスキーマではコストがかかる可能性があり、 TypeScriptの制限 により、呼び出しが連鎖すると二次関数的にコストが増加します
  4. 必要に応じて、 z.strictObject() または z.looseObject() を使用して、結果のスキーマの厳密性レベルを変更できます

.safeExtend()

.safeExtend() メソッドは .extend() と同様に機能しますが、割り当て不可能なスキーマで既存のプロパティを上書きすることはできません。つまり、 .safeExtend() の結果は、元のスキーマを(TypeScriptの意味で) extends する推論された型を持ちます。

z.object({ a: z.string() }).safeExtend({ a: z.string().min(5) }); // ✅
z.object({ a: z.string() }).safeExtend({ a: z.any() }); // ✅
z.object({ a: z.string() }).safeExtend({ a: z.number() });
//                                       ^  ❌ ZodNumber is not assignable 

refinements(改善)を含むスキーマを拡張するには .safeExtend() を使用してください。(通常の .extend() は、refinementsを持つスキーマで使用されるとエラーをスローします。)

const Base = z.object({
  a: z.string(),
  b: z.string()
}).refine(user => user.a === user.b);
 
// Extended inherits the refinements of Base
const Extended = Base.safeExtend({
  a: z.string().min(10)
});

.pick()

TypeScriptの組み込みユーティリティ型 PickOmit に触発され、Zodはオブジェクトスキーマから特定のキーを選択および除外するための専用APIを提供します。

この初期スキーマから始めます:

const Recipe = z.object({
  title: z.string(),
  description: z.string().optional(),
  ingredients: z.array(z.string()),
});
// { title: string; description?: string | undefined; ingredients: string[] }

特定のキーを選択(pick)するには:

const JustTheTitle = Recipe.pick({ title: true });

.omit()

特定のキーを除外(omit)するには:

const RecipeNoId = Recipe.omit({ id: true });

.partial()

便利なように、Zodは一部またはすべてのプロパティをオプショナルにするための専用APIを提供しています。これは組み込みのTypeScriptユーティリティ型 Partial に触発されています。

すべてのフィールドをオプショナルにするには:

const PartialRecipe = Recipe.partial();
// { title?: string | undefined; description?: string | undefined; ingredients?: string[] | undefined }

特定のプロパティをオプショナルにするには:

const RecipeOptionalIngredients = Recipe.partial({
  ingredients: true,
});
// { title: string; description?: string | undefined; ingredients?: string[] | undefined }

.required()

Zodは一部またはすべてのプロパティを必須にするAPIを提供しています。これはTypeScriptの Required ユーティリティ型に触発されています。

すべてのプロパティを必須にするには:

const RequiredRecipe = Recipe.required();
// { title: string; description: string; ingredients: string[] }

特定のプロパティを必須にするには:

const RecipeRequiredDescription = Recipe.required({description: true});
// { title: string; description: string; ingredients: string[] }

再帰的オブジェクト (Recursive objects)

自己参照型を定義するには、キーに getter を使用します。これにより、JavaScriptは実行時に循環スキーマを解決できます。

const Category = z.object({
  name: z.string(),
  get subcategories(){
    return z.array(Category)
  }
});
 
type Category = z.infer<typeof Category>;
// { name: string; subcategories: Category[] }

再帰的スキーマはサポートされていますが、Zodに循環データを渡すと無限ループが発生します。

相互再帰型を表すこともできます:

const User = z.object({
  email: z.email(),
  get posts(){
    return z.array(Post)
  }
});
 
const Post = z.object({
  title: z.string(),
  get author(){
    return User
  }
});

すべてのオブジェクトAPI(.pick(), .omit(), .required(), .partial() など)は期待通りに機能します。

循環エラー (Circularity errors)

TypeScriptの制限により、再帰的な型推論は扱いにくく、特定のシナリオでしか機能しません。より複雑な型では、次のような再帰型エラーが発生する可能性があります:

const Activity = z.object({
  name: z.string(),
  get subactivities() {
    // ^ ❌ 'subactivities' implicitly has return type 'any' because it does not
    // have a return type annotation and is referenced directly or indirectly
    // in one of its return expressions.ts(7023)
 
    return z.nullable(z.array(Activity));
  },
});

このような場合、問題のあるgetterに型注釈を付けることでエラーを解決できます:

const Activity = z.object({
  name: z.string(),
  get subactivities(): z.ZodNullable<z.ZodArray<typeof Activity>> {
    return z.nullable(z.array(Activity));
  },
});

配列 (Arrays)

配列スキーマを定義するには:

const stringArray = z.array(z.string()); // or z.string().array()

配列の要素の内部スキーマにアクセスするには:

stringArray.unwrap(); // => string schema

Zodは、配列固有のバリデーションをいくつか実装しています:

z.array(z.string()).min(5); // must contain 5 or more items
z.array(z.string()).max(5); // must contain 5 or fewer items
z.array(z.string()).length(5); // must contain 5 items exactly

タプル (Tuples)

配列とは異なり、タプルは通常、各インデックスに対して異なるスキーマを指定する固定長の配列です。

const MyTuple = z.tuple([
  z.string(),
  z.number(),
  z.boolean()
]);
 
type MyTuple = z.infer<typeof MyTuple>;
// [string, number, boolean]

可変長("rest")引数を追加するには:

const variadicTuple = z.tuple([z.string()], z.number());
// => [string, ...number[]];

ユニオン (Unions)

ユニオン型 (A | B) は論理的な "OR" を表します。Zodのユニオン・スキーマは、入力を各オプションに対して順番にチェックします。最初に正常に検証された値が返されます。

const stringOrNumber = z.union([z.string(), z.number()]);
// string | number
 
stringOrNumber.parse("foo"); // passes
stringOrNumber.parse(14); // passes

内部のオプション・スキーマを抽出するには:

stringOrNumber.options; // [ZodString, ZodNumber]

判別可能なユニオン (Discriminated unions)

判別可能なユニオン は、a) すべてのオプションがオブジェクトスキーマであり、b) 特定のキー(「判別子」)を共有している、特別な種類のユニオンです。判別子キーの値に基づいて、TypeScriptは型シグネチャを期待通りに「絞り込む」ことができます。

type MyResult =
  | { status: "success"; data: string }
  | { status: "failed"; error: string };
 
function handleResult(result: MyResult){
  if(result.status === "success"){
    result.data; // string
  } else {
    result.error; // string
  }
}

通常の z.union() でこれを表現することもできます。しかし、通常のユニオンは ナイーブ です — 入力を各オプションに対して順番にチェックし、最初に通過したものを返します。これは大規模なユニオンでは遅くなる可能性があります。

そのため、Zodは 判別子キー を使用して解析をより効率的に行う z.discriminatedUnion() APIを提供しています。

const MyResult = z.discriminatedUnion("status", [
  z.object({ status: z.literal("success"), data: z.string() }),
  z.object({ status: z.literal("failed"), error: z.string() }),
]);

各オプションは、判別プロパティ(上記の例では status)が特定のリテラル値または値のセットに対応する オブジェクトスキーマ でなければなりません。通常は z.enum(), z.literal(), z.null(), または z.undefined() です。

インターセクション (Intersections)

インターセクション型 (A & B) は論理的な "AND" を表します。

const a = z.union([z.number(), z.string()]);
const b = z.union([z.number(), z.boolean()]);
const c = z.intersection(a, b);
 
type c = z.infer<typeof c>; // => number

これは2つのオブジェクト型を交差させるのに便利です。

const Person = z.object({ name: z.string() });
type Person = z.infer<typeof Person>;
 
const Employee = z.object({ role: z.string() });
type Employee = z.infer<typeof Employee>;
 
const EmployedPerson = z.intersection(Person, Employee);
type EmployedPerson = z.infer<typeof EmployedPerson>;
// Person & Employee

オブジェクトスキーマをマージする場合は、インターセクションよりも A.extend(B) を優先してください。 .extend() を使用すると新しいオブジェクトスキーマが得られますが、 z.intersection(A, B)pickomit などの一般的なオブジェクトメソッドを欠く ZodIntersection インスタンスを返します。

レコード (Records)

レコードスキーマは Record<string, string> のような型を検証するために使用されます。

const IdCache = z.record(z.string(), z.string());
type IdCache = z.infer<typeof IdCache>; // Record<string, string>
 
IdCache.parse({
  carlotta: "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd",
  jimmie: "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd",
});

キースキーマは string | number | symbol に割り当て可能な任意のZodスキーマにすることができます。

const Keys = z.union([z.string(), z.number(), z.symbol()]);
const AnyObject = z.record(Keys, z.unknown());
// Record<string | number | symbol, unknown>

enumで定義されたキーを含むオブジェクトスキーマを作成するには:

const Keys = z.enum(["id", "name", "email"]);
const Person = z.record(Keys, z.string());
// { id: string; name: string; email: string }

Zod 4 — Zod 4では、 z.record() の最初の引数に z.enum を渡すと、Zodはすべてのenum値がキーとして入力に存在することを網羅的にチェックします。この動作はTypeScriptと一致しています:

type MyRecord = Record<"a" | "b", string>;
const myRecord: MyRecord = { a: "foo", b: "bar" }; // ✅
const myRecord: MyRecord = { a: "foo" }; // ❌ missing required key `b`

Zod 3では、網羅性はェックされていませんでした。古い動作を再現するには、 z.partialRecord() を使用してください。

部分的なレコード型が必要な場合は、 z.partialRecord() を使用してください。これは、Zodが z.enum() および z.literal() キースキーマで通常実行する特別な網羅性チェックをスキップします。

const Keys = z.enum(["id", "name", "email"]).or(z.never()); 
const Person = z.partialRecord(Keys, z.string());
// { id?: string; name?: string; email?: string }

マップ (Maps)

const StringNumberMap = z.map(z.string(), z.number());
type StringNumberMap = z.infer<typeof StringNumberMap>; // Map<string, number>
 
const myMap: StringNumberMap = new Map();
myMap.set("one", 1);
myMap.set("two", 2);
 
StringNumberMap.parse(myMap);

セット (Sets)

const NumberSet = z.set(z.number());
type NumberSet = z.infer<typeof NumberSet>; // Set<number>
 
const mySet: NumberSet = new Set();
mySet.add(1);
mySet.add(2);
NumberSet.parse(mySet);

セットスキーマは、以下のユーティリティメソッドを使用してさらに制約することができます。

z.set(z.string()).min(5); // must contain 5 or more items
z.set(z.string()).max(5); // must contain 5 or fewer items
z.set(z.string()).size(5); // must contain 5 items exactly

ファイル (Files)

File インスタンスを検証するには:

const fileSchema = z.file();
 
fileSchema.min(10_000); // minimum .size (bytes)
fileSchema.max(1_000_000); // maximum .size (bytes)
fileSchema.mime("image/png"); // MIME type
fileSchema.mime(["image/png", "image/jpeg"]); // multiple MIME types

プロミス (Promises)

非推奨z.promise() はZod 4で非推奨になりました。 Promise スキーマの有効なユースケースはほとんどありません。値が Promise である可能性があると思われる場合は、Zodで解析する前に単純に await してください。

Instanceof

入力がクラスのインスタンスであることを確認するには z.instanceof を使用できます。これは、サードパーティライブラリからエクスポートされたクラスに対して入力を検証するのに便利です。

class Test {
  name: string;
}
 
const TestSchema = z.instanceof(Test);
 
TestSchema.parse(new Test()); // ✅
TestSchema.parse("whatever"); // ❌

プロパティ (Property)

Zodスキーマに対してクラスインスタンスの特定のプロパティを検証するには:

const blobSchema = z.instanceof(URL).check(
  z.property("protocol", z.literal("https:" as string, "Only HTTPS allowed"))
);
 
blobSchema.parse(new URL("https://example.com")); // ✅
blobSchema.parse(new URL("http://example.com")); // ❌

z.property() APIは任意のデータ型で動作します(ただし、 z.instanceof() と組み合わせて使用する場合に最も便利です)。

const blobSchema = z.string().check(
  z.property("length", z.number().min(10))
);
 
blobSchema.parse("hello there!"); // ✅
blobSchema.parse("hello."); // ❌

洗練 (Refinements)

すべてのZodスキーマは、 refinements の配列を保持しています。Refinementは、ZodがネイティブAPIを提供していないカスタムバリデーションを実行する方法です。

.refine()

const myString = z.string().refine((val) => val.length <= 255);

Refinementの関数は決してスローしてはなりません。代わりに、失敗を通知するためにfalsy値を返す必要があります。スローされたエラーはZodによってキャッチされません。

error

エラーメッセージをカスタマイズするには:

const myString = z.string().refine((val) => val.length > 8, { 
  error: "Too short!" 
});

abort

デフォルトでは、チェックからの検証問題は 継続可能 (continuable) と見なされます。つまり、Zodは、そのうちの1つが検証エラーを引き起こしたとしても、 すべて のチェックを順番に実行します。これは通常、Zodができるだけ多くのエラーを一度に表面化できることを意味するため、望ましい動作です。

const myString = z.string()
  .refine((val) => val.length > 8, { error: "Too short!" })
  .refine((val) => val === val.toLowerCase(), { error: "Must be lowercase" });
  
 
const result = myString.safeParse("OH NO");
result.error?.issues;
/* [
  { "code": "custom", "message": "Too short!" },
  { "code": "custom", "message": "Must be lowercase" }
] */

特定のrefinementを 継続不可能 (non-continuable) としてマークするには、 abort パラメータを使用します。チェックが失敗した場合、バリデーションは終了します。

const myString = z.string()
  .refine((val) => val.length > 8, { error: "Too short!", abort: true })
  .refine((val) => val === val.toLowerCase(), { error: "Must be lowercase", abort: true });
 
 
const result = myString.safeParse("OH NO");
result.error?.issues;
// => [{ "code": "custom", "message": "Too short!" }]

path

エラーパスをカスタマイズするには、 path パラメータを使用します。これは通常、オブジェクトスキーマのコンテキストでのみ役立ちます。

const passwordForm = z
  .object({
    password: z.string(),
    confirm: z.string(),
  })
  .refine((data) => data.password === data.confirm, {
    message: "Passwords don't match",
    path: ["confirm"], // path of error
  });

これにより、関連する問題の path パラメータが設定されます:

const result = passwordForm.safeParse({ password: "asdf", confirm: "qwer" });
result.error.issues;
/* [{
  "code": "custom",
  "path": [ "confirm" ],
  "message": "Passwords don't match"
}] */

非同期のrefinementを定義するには、 async 関数を渡すだけです:

const userId = z.string().refine(async (id) => {
  // verify that ID exists in database
  return true;
});

非同期refinementを使用する場合は、データを解析するために .parseAsync メソッドを使用する必要があります!そうしないと、Zodはエラーをスローします。

const result = await userId.parseAsync("abc123");

when

Note — これはパワーユーザー向けの機能であり、refinement内部から捕捉されないエラーが発生する確率を高めるような方法で悪用される可能性があります。

デフォルトでは、すでに 継続不可能 (non-continuable) な問題が発生している場合、refinementは実行されません。Zodは、refinement関数に値を渡す前に、値の型シグネチャが正しいことを保証するように注意しています。

const schema = z.string().refine((val) => {
  return val.length > 8
});
 
schema.parse(1234); // invalid_type: refinement won't be executed

場合によっては、refinementを実行するタイミングを細かく制御したいことがあります。たとえば、この「パスワード確認」チェックを考えてみましょう:

const schema = z
  .object({
    password: z.string().min(8),
    confirmPassword: z.string(),
    anotherField: z.string(),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: "Passwords do not match",
    path: ["confirmPassword"],
  });
 
schema.parse({
  password: "asdf",
  confirmPassword: "asdf",
  anotherField: 1234 // ❌ this error will prevent the password check from running
});

anotherField のエラーは、パスワード確認チェックが anotherField に依存していなくても、チェックの実行を妨げます。refinementを実行するタイミングを制御するには、 when パラメータを使用します。

const schema = z
  .object({
    password: z.string().min(8),
    confirmPassword: z.string(),
    anotherField: z.string(),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: "Passwords do not match",
    path: ["confirmPassword"],
 
    // run if password & confirmPassword are valid
    when(payload) { 
      return schema 
        .pick({ password: true, confirmPassword: true }) 
        .safeParse(payload.value).success; 
    },  
  });
 
schema.parse({
  password: "asdf",
  confirmPassword: "asdf",
  anotherField: 1234 // ❌ this error will not prevent the password check from running
});

.superRefine()

通常の .refine APIは "custom" エラーコードを持つ単一の問題のみを生成しますが、 .superRefine() を使用すると、Zodの内部問題タイプのいずれかを使用して複数の問題を作成できます。

const UniqueStringArray = z.array(z.string()).superRefine((val, ctx) => {
  if (val.length > 3) {
    ctx.addIssue({
      code: "too_big",
      maximum: 3,
      origin: "array",
      inclusive: true,
      message: "Too many items 😡",
      input: val,
    });
  }
 
  if (val.length !== new Set(val).size) {
    ctx.addIssue({
      code: "custom",
      message: `No duplicates allowed.`,
      input: val,
    });
  }
});
 

.check()

Note.check() APIは .superRefine() よりも一般的により複雑な、低レベルのAPIです。パフォーマンスに敏感なコードパスでは高速になる可能性がありますが、記述が冗長になります。

コーデック (Codecs)

New — Zod 4.1で導入されました。詳細については、専用の Codecs ページを参照してください。

コーデックは、2つの他のスキーマ間の 双方向変換 を実装する特別な種類のスキーマです。

const stringToDate = z.codec(
  z.iso.datetime(),  // input schema: ISO date string
  z.date(),          // output schema: Date object
  {
    decode: (isoString) => new Date(isoString), // ISO string → Date
    encode: (date) => date.toISOString(),       // Date → ISO string
  }
);

通常の .parse() 操作は 順方向変換 を実行します。これはコーデックの decode 関数を呼び出します。

stringToDate.parse("2024-01-15T10:30:00.000Z"); // => Date

代わりにトップレベルの z.decode() 関数を使用することもできます。 .parse()unknown 入力を受け入れる)とは異なり、 z.decode() は強く型付けされた入力(この例では string )を期待します。

z.decode(stringToDate, "2024-01-15T10:30:00.000Z"); // => Date

逆方向変換 を実行するには、逆の z.encode() を使用します。

z.encode(stringToDate, new Date("2024-01-15")); // => "2024-01-15T00:00:00.000Z"

詳細については、専用の Codecs ページを参照してください。そのページには、プロジェクトにコピー&ペーストできる一般的に必要なコーデックの実装が含まれています:

パイプ (Pipes)

スキーマは「パイプ」として連鎖させることができます。パイプは主に Transforms と組み合わせて使用する場合に便利です。

const stringToLength = z.string().pipe(z.transform(val => val.length));
 
stringToLength.parse("hello"); // => 5

トランスフォーム (Transforms)

Note — 双方向変換の場合は、 codecs を使用してください。

トランスフォームは、単方向変換を実行する特別な種類のスキーマです。入力を検証する代わりに、あらゆるものを受け入れ、データに対して何らかの変換を実行します。トランスフォームを定義するには:

const castToString = z.transform((val) => String(val));
 
castToString.parse("asdf"); // => "asdf"
castToString.parse(123); // => "123"
castToString.parse(true); // => "true"

トランスフォーム関数は決してスローしてはなりません。スローされたエラーはZodによってキャッチされません。

トランスフォーム内でバリデーションロジックを実行するには、 ctx を使用します。バリデーションの問題を報告するには、 ctx.issues に新しい問題をプッシュします( .check() APIと同様です)。

const coercedInt = z.transform((val, ctx) => {
  try {
    const parsed = Number.parseInt(String(val));
    return parsed;
  } catch (e) {
    ctx.issues.push({
      code: "custom",
      message: "Not a number",
      input: val,
    });
 
    // this is a special constant with type `never`
    // returning it lets you exit the transform without impacting the inferred return type
    return z.NEVER;
  }
});

最も一般的には、トランスフォームは Pipes と組み合わせて使用されます。この組み合わせは、いくつかの初期バリデーションを実行し、その後、解析されたデータを別の形式に変換する場合に役立ちます。

const stringToLength = z.string().pipe(z.transform(val => val.length));
 
stringToLength.parse("hello"); // => 5

.transform()

スキーマをトランスフォームにパイプするのは一般的なパターンであるため、Zodは便利な .transform() メソッドを提供しています。

const stringToLength = z.string().transform(val => val.length); 

トランスフォームは非同期にすることもできます:

const idToUser = z
  .string()
  .transform(async (id) => {
    // fetch user from database
    return db.getUserById(id); 
  });
 
const user = await idToUser.parseAsync("abc123");

非同期トランスフォームを使用する場合は、データを解析する際に .parseAsync または .safeParseAsync を使用する必要があります!そうしないと、Zodはエラーをスローします。

.preprocess()

トランスフォームを別のスキーマにパイプするのも一般的なパターンであるため、Zodは便利な z.preprocess() 関数を提供しています。

const coercedInt = z.preprocess((val) => {
  if (typeof val === "string") {
    return Number.parseInt(val);
  }
  return val;
}, z.int());

デフォルト (Defaults)

スキーマにデフォルト値を設定するには:

const defaultTuna = z.string().default("tuna");
 
defaultTuna.parse(undefined); // => "tuna"

あるいは、デフォルト値を生成する必要があるたびに再実行される関数を渡すこともできます:

const randomDefault = z.number().default(Math.random);
 
randomDefault.parse(undefined);    // => 0.4413456736055323
randomDefault.parse(undefined);    // => 0.1871840107401901
randomDefault.parse(undefined);    // => 0.7223408162401552

プリフォルト (Prefaults)

Zodでは、 デフォルト 値を設定すると、解析プロセスがショートサーキット(短絡)されます。入力が undefined の場合、デフォルト値が即座に返されます。そのため、デフォルト値はスキーマの 出力型 に割り当て可能でなければなりません。

const schema = z.string().transform(val => val.length).default(0);
schema.parse(undefined); // => 0

場合によっては、 プリフォルト ("解析前デフォルト")値を定義すると便利です。入力が undefined の場合、代わりにプリフォルト値が解析されます。解析プロセスはショートサーキット されません 。そのため、プリフォルト値はスキーマの 入力型 に割り当て可能でなければなりません。

z.string().transform(val => val.length).prefault("tuna");
schema.parse(undefined); // => 4

これは、変更を伴うrefinementを通して何らかの入力値を渡したい場合にも役立ちます。

const a = z.string().trim().toUpperCase().prefault("  tuna  ");
a.parse(undefined); // => "TUNA"
 
const b = z.string().trim().toUpperCase().default("  tuna  ");
b.parse(undefined); // => "  tuna  "

キャッチ (Catch)

検証エラーが発生した場合に返されるフォールバック値を定義するには、 .catch() を使用します:

const numberWithCatch = z.number().catch(42);
 
numberWithCatch.parse(5); // => 5
numberWithCatch.parse("tuna"); // => 42

あるいは、キャッチ値を生成する必要があるたびに再実行される関数を渡すこともできます。

const numberWithRandomCatch = z.number().catch((ctx) => {
  ctx.error; // the caught ZodError
  return Math.random();
});
 
numberWithRandomCatch.parse("sup"); // => 0.4413456736055323
numberWithRandomCatch.parse("sup"); // => 0.1871840107401901
numberWithRandomCatch.parse("sup"); // => 0.7223408162401552

ブランド型 (Branded types)

TypeScriptの型システムは 構造的 (structural) です。つまり、構造的に等価な2つの型は同じものと見なされます。

type Cat = { name: string };
type Dog = { name: string };
 
const pluto: Dog = { name: "pluto" };
const simba: Cat = pluto; // works fine

TypeScript内部で 公称的型付け (nominal typing) をシミュレートすることが望ましい場合があります。これは ブランド型 (または "opaque types")で実現できます。

const Cat = z.object({ name: z.string() }).brand<"Cat">();
const Dog = z.object({ name: z.string() }).brand<"Dog">();
 
type Cat = z.infer<typeof Cat>; // { name: string } & z.$brand<"Cat">
type Dog = z.infer<typeof Dog>; // { name: string } & z.$brand<"Dog">
 
const pluto = Dog.parse({ name: "pluto" });
const simba: Cat = pluto; // ❌ not allowed

内部的には、これはスキーマの推論された型に "ブランド" を付加することで機能します。

const Cat = z.object({ name: z.string() }).brand<"Cat">();
type Cat = z.infer<typeof Cat>; // { name: string } & z.$brand<"Cat">

このブランドがあるため、プレーンな(ブランド化されていない)データ構造は推論された型に割り当てることはできなくなります。ブランド化されたデータを取得するには、スキーマを使用してデータを解析する必要があります。

ブランド型は .parse の実行時の結果には影響しないことに注意してください。これは静的な構成要素にすぎません。

読み取り専用 (Readonly)

スキーマを読み取り専用としてマークするには:

const ReadonlyUser = z.object({ name: z.string() }).readonly();
type ReadonlyUser = z.infer<typeof ReadonlyUser>;
// Readonly<{ name: string }>

新しいスキーマの推論された型は readonly としてマークされます。TypeScriptでは、これはオブジェクト、配列、タプル、 Set 、および Map にのみ影響することに注意してください:

z.object({ name: z.string() }).readonly(); // { readonly name: string }
z.array(z.string()).readonly(); // readonly string[]
z.tuple([z.string(), z.number()]).readonly(); // readonly [string, number]
z.map(z.string(), z.date()).readonly(); // ReadonlyMap<string, Date>
z.set(z.string()).readonly(); // ReadonlySet<string>

入力は通常どおり解析され、結果は変更を防ぐために Object.freeze() で凍結されます。

const result = ReadonlyUser.parse({ name: "fido" });
result.name = "simba"; // throws TypeError

JSON

JSONエンコード可能な値を検証するには:

const jsonSchema = z.json();

これは、次のユニオン・スキーマを返す便利なAPIです:

const jsonSchema = z.lazy(() => {
  return z.union([
    z.string(params), 
    z.number(), 
    z.boolean(), 
    z.null(), 
    z.array(jsonSchema), 
    z.record(z.string(), jsonSchema)
  ]);
});

関数 (Functions)

Zodは、Zodで検証された関数を定義するための z.function() ユーティリティを提供しています。これにより、バリデーションコードとビジネスロジックが混在するのを避けることができます。

const MyFunction = z.function({
  input: [z.string()], // parameters (must be an array or a ZodTuple)
  output: z.number()  // return type
});
 
type MyFunction = z.infer<typeof MyFunction>;
// (input: string) => number

関数スキーマには .implement() メソッドがあり、これに関数を渡すと、入力と出力を自動的に検証する新しい関数を返します。

const computeTrimmedLength = MyFunction.implement((input) => {
  // TypeScript knows input is a string!
  return input.trim().length;
});
 
computeTrimmedLength("sandwich"); // => 8
computeTrimmedLength(" asdf "); // => 4

入力が無効な場合、この関数は ZodError をスローします:

computeTrimmedLength(42); // throws ZodError

入力の検証のみに関心がある場合は、 output フィールドを省略できます。

const MyFunction = z.function({
  input: [z.string()], // parameters (must be an array or a ZodTuple)
});
 
const computeTrimmedLength = MyFunction.implement((input) => input.trim.length);

非同期関数を作成するには、 .implementAsync() メソッドを使用します。

const computeTrimmedLengthAsync = MyFunction.implementAsync(
  async (input) => input.trim().length
);
 
computeTrimmedLengthAsync("sandwich"); // => Promise<8>

カスタム (Custom)

z.custom() を使用して、任意のTypeScript型のZodスキーマを作成できます。これは、テンプレート文字列リテラルなど、Zodが標準でサポートしていない型のスキーマを作成する場合に便利です。

const px = z.custom<`${number}px`>((val) => {
  return typeof val === "string" ? /^\d+px$/.test(val) : false;
});
 
type px = z.infer<typeof px>; // `${number}px`
 
px.parse("42px"); // "42px"
px.parse("42vw"); // throws;

バリデーション関数を提供しない場合、Zodはあらゆる値を許可します。これは危険な場合があります!

z.custom<{ arg: string }>(); // performs no validation

2番目の引数を渡すことで、エラーメッセージやその他のオプションをカスタマイズできます。このパラメータは .refine のparamsパラメータと同じように機能します。

z.custom<...>((val) => ..., "custom error message");

On this page

プリミティブ (Primitives)
Coercion (強制型変換)
リテラル (Literals)
文字列 (Strings)
文字列フォーマット (String formats)
メールアドレス (Emails)
UUID
URL
ISO 日時 (ISO datetimes)
ISO 日付 (ISO dates)
ISO 時刻 (ISO times)
IPアドレス (IP addresses)
IPブロック (CIDR) (IP blocks (CIDR))
MACアドレス (MAC Addresses)
JWT (JWTs)
ハッシュ (Hashes)
カスタムフォーマット (Custom formats)
テンプレートリテラル (Template literals)
数値 (Numbers)
整数 (Integers)
BigInt (BigInts)
ブール値 (Booleans)
日付 (Dates)
列挙型 (Enums)
.enum
.exclude()
.extract()
ブール文字列 (Stringbools)
オプショナル (Optionals)
ヌーラブル (Nullables)
Nullish
Unknown
Never
オブジェクト (Objects)
z.strictObject
z.looseObject
.catchall()
.shape
.keyof()
.extend()
.safeExtend()
.pick()
.omit()
.partial()
.required()
再帰的オブジェクト (Recursive objects)
循環エラー (Circularity errors)
配列 (Arrays)
タプル (Tuples)
ユニオン (Unions)
判別可能なユニオン (Discriminated unions)
インターセクション (Intersections)
レコード (Records)
マップ (Maps)
セット (Sets)
ファイル (Files)
プロミス (Promises)
Instanceof
プロパティ (Property)
洗練 (Refinements)
.refine()
.superRefine()
.check()
コーデック (Codecs)
パイプ (Pipes)
トランスフォーム (Transforms)
.transform()
.preprocess()
デフォルト (Defaults)
プリフォルト (Prefaults)
キャッチ (Catch)
ブランド型 (Branded types)
読み取り専用 (Readonly)
JSON
関数 (Functions)
カスタム (Custom)