型の冒険者よ、ようこそ!🎩 TypeScriptって素晴らしいですよね?静的型付けによってコードの構造化を助け、イライラするバグを防いでくれます。ですが、ここで注目したいのは:TypeScriptは型チェックを...コンパイル時にしか行わないのです!😬 つまり、コードが実行されている時、外部ソース(API、ユーザーなど)から来るデータが期待される構造を守るという保証はないのです。そこでZodの出番です!🚀
この記事では、動的にデータを検証し型付けすることができるライブラリ、Zodの使用方法とその理由について探っていきます。基本的なバリデーションから複雑なデータ構造まで、Zodは妥協のないTypeScriptデータの安全性を確保するために必要なすべてを提供します。さあ、始めましょう!🎉
Zodとは?🤔
ZodはリアルタイムでデータをチェックするTypeScriptスキーマバリデーションライブラリです。Zodを使用すると、あらゆる種類のオブジェクトに対してバリデーションスキーマを作成できます。不確実なデータを返すAPIを想像してみてください:Zodは受け取ったデータが期待される型と一致するかをその場で確認できます。
Zodの主な特徴 💪
- シンプルで柔軟:直感的で表現力豊かな構文
- バリデーションと型付けの統合:別々の型とバリデーションを扱う必要なし!
- 即時フィードバック:データがスキーマと一致しない場合、詳細なエラーをすぐに受け取れます
- 堅牢なAPI:シンプルなバリデーションから複雑な変換まで、完全なAPIを提供
Zodのインストール 📦
まずは、npmやyarnでZodをインストールします:
準備ができたら、最初のZodスキーマを作成してみましょう!
Zodで基本的なスキーマを作成する 🎨
Zodスキーマは期待されるデータ構造を表します。名前、年齢、メールアドレスを持つユーザーを検証する簡単な例を見てみましょう。
例:基本的なバリデーション
ユーザーのZodスキーマを定義する方法はこちらです 👤:
このZodスキーマは、userInput
が定義されたuserSchema
を遵守しているかを確認します。すべて正常な場合、parse
は検証済みのデータを返します。そうでない場合は、何が間違っているのかを詳しく説明したエラーメッセージが投げられます。本番環境でも予期せぬ問題は起きません!🎉
条件付き型とユニオン:複数のケースを扱う 🔀
Zodは条件付き型を使用して複雑なスキーマも扱えます。ユーザーがクライアントまたは管理者のいずれかになりうるフォームがあるとしましょう。Zodでこのスキーマを定義する方法を見てみましょう。
例:ユニオンスキーマ
この例では、ZodはadminUser
がclient
またはadmin
のいずれかで、それぞれの役割に必要なプロパティを持っているかを検証します。便利ですよね?👌
変換:バリデーションと同時に変換する 🔄
データの検証と変換を同時に行いたい場合があります。Zodは文字列を数値に変換するなど、これを簡単に実現できます。
例:データ変換
ここでは、Zodは文字列("49.99"
)を受け取り、有効な数値に変換します。
カスタムバリデーション 🛠️
Zodは.refine()
メソッドを使用してカスタムバリデーションを作成することもできます。最小長さや特殊文字などの特定の基準でパスワードを検証したい場合を見てみましょう。
例:パスワードバリデーション
.refine()
メソッドでカスタム条件を追加できます。ここでは、Zodはパスワードが定義された基準を満たしているかをチェックし、満たしていない場合は具体的なエラーメッセージを提供します。
なぜZodを選ぶのか?🌟
Zodは以下の理由でTypeScriptのバリデーションに不可欠となっています:
- 複雑さを増すことなく、バリデーションと型付けを完璧に組み合わせます
- 複雑なスキーマでも明確で直感的なAPIを提供します
- 理解しやすくデバッグが容易なエラーを提供します
- TypeScriptプロジェクトに完璧に統合できます
まとめ
Zodは受け取ったデータを動的に検証することで、TypeScriptにさらなるセキュリティと信頼性の層を追加します。データが健全で適切に型付けされていることを確信して、安心して眠れるでしょう。次のプロジェクトでZodを試してみる準備はできましたか?😎
1import { z } from 'zod';
2
3// ユーザースキーマ
4const userSchema = z.object({
5 name: z.string(), // 名前は文字列である必要があります
6 age: z.number().int().min(18), // 年齢は整数で、最低18である必要があります
7 email: z.string().email(), // 有効なメールアドレスである必要があります
8});
9
10// 入力データの例
11const userInput = {
12 name: 'Alice',
13 age: 25,
14 email: 'alice@example.com',
15};
16
17// データバリデーション
18try {
19 const validUser = userSchema.parse(userInput); // parseは検証済みデータを返します
20 console.log('有効なユーザー:', validUser);
21} catch (e) {
22 console.error('バリデーションエラー:', e.errors);
23}
1// クライアントスキーマ
2const clientSchema = z.object({
3 role: z.literal('client'),
4 preferences: z.array(z.string()), // 設定の配列
5});
6
7// 管理者スキーマ
8const adminSchema = z.object({
9 role: z.literal('admin'),
10 accessLevel: z.number().min(1).max(5), // アクセスレベル1から5
11});
12
13// 両方のスキーマのユニオン
14const userSchema = z.union([clientSchema, adminSchema]);
15
16// ユーザーの例
17const adminUser = {
18 role: 'admin',
19 accessLevel: 3,
20};
21
22// バリデーション
23try {
24 const validUser = userSchema.parse(adminUser);
25 console.log('有効なユーザー:', validUser);
26} catch (e) {
27 console.error('バリデーションエラー:', e.errors);
28}
1const passwordSchema = z
2 .string()
3 .min(8, { message: 'パスワードは最低8文字必要です' })
4 .refine((val) => /[A-Z]/.test(val), {
5 message: 'パスワードは少なくとも1つの大文字を含む必要があります',
6 })
7 .refine((val) => /[0-9]/.test(val), {
8 message: 'パスワードは少なくとも1つの数字を含む必要があります',
9 });
10
11// 入力例
12const passwordInput = 'Secure123';
13
14// バリデーション
15try {
16 const validPassword = passwordSchema.parse(passwordInput);
17 console.log('有効なパスワード:', validPassword);
18} catch (e) {
19 console.error('バリデーションエラー:', e.errors);
20}