03 / 09
Zod ile şema ve doğrulama
Zod 4 ile şema yazmak, parse ve safeParse, tip çıkarımı, hata mesajlarını özelleştirmek, alanlar arası kural, dönüşüm, boş alan tuzakları, hata biçimlendirme ve Türkçe mesajlar.
Neden Şema?
TypeScript tipleri derlemeden sonra silinir. Formdan, URL'den ya da bir API'den gelen veri çalışma anında ne olduğunu bilmediğiniz bir değerdir. Zod bu değeri bir şemaya göre doğrular ve aynı şemadan TypeScript tipini çıkarır. Böylece kural ve tip tek bir yerde durur.1
Bu ders Zod 4.6 ile yazıldı:2
$ pnpm add zodİlk Şema
import { z } from "zod";
export const signUpSchema = z.object({
name: z.string().trim().min(2),
email: z.email(),
age: z.number().int().min(18),
newsletter: z.boolean(),
});
export type SignUp = z.infer<typeof signUpSchema>;
// { name: string; email: string; age: number; newsletter: boolean }Zod 4'te e-posta, URL ve UUID gibi biçimler üst düzey fonksiyonlardır: z.email(), z.url(), z.uuid(). Eski z.string().email() yazımı çalışır ama kullanımdan kaldırılmıştır.34
parse ve safeParse
signUpSchema.parse(input); // geçersizse ZodError fırlatır
const result = signUpSchema.safeParse(input);
if (!result.success) {
console.log(result.error.issues);
} else {
result.data; // SignUp tipinde, temizlenmiş veri
}Formlarda ve Server Action'larda safeParse kullanın; hata beklenen bir durumdur, istisna değil.1 Yalnızca evet/hayır gerekiyorsa Zod 4.6 ile gelen .validate() hata nesnesi kurmadan boolean döndürür:5
if (signUpSchema.validate(input)) {
input.email; // tip daraltıldı
}Hata Mesajlarını Özelleştirmek
Zod 4'te mesaj, error parametresiyle ya da doğrudan metinle verilir:6
z.string().min(2, "Ad en az 2 karakter olmalı.");
z.string().min(2, { error: "Ad en az 2 karakter olmalı." });
z.number({ error: "Yaşınızı girin." }); // tip hatası içinZod 3'teki message, invalid_type_error ve required_error yerine artık tek parametre error var. İnternetteki eski örneklerde (Next.js'in form rehberindeki örnek dahil) hâlâ bu adları görebilirsiniz.7
Türkçe varsayılan mesajlar. Zod'un yerleşik dil paketleri var. Uygulamanın girişinde bir kez ayarlayın:6
import { z } from "zod";
import { tr } from "zod/locales";
z.config(tr());
z.string().min(2).safeParse("a").error?.issues[0].message;
// "Çok küçük: beklenen string >=2 karakter"Bu mesajlar geneldir ve son kullanıcı için teknik kalır. Kullanıcının göreceği alanlarda kendi mesajınızı yazın; dil paketi unuttuğunuz yerler için güvenlik ağıdır.
Alanlar Arası Kural
Bir kural birden fazla alana bakıyorsa nesneye .refine ekleyin. path hatanın hangi alana yazılacağını seçer:8
const passwordSchema = z
.object({
password: z.string().min(8, "Şifre en az 8 karakter olmalı."),
confirmPassword: z.string(),
})
.refine((data) => data.password === data.confirmPassword, {
error: "Şifreler eşleşmiyor.",
path: ["confirmPassword"],
});Warning
Nesnedeki bir alanda tip hatası varsa (seçilmemiş enum, NaN sayı) nesnenin .refine'ı hiç çalışmaz. Zod refinement'a yalnızca tipi doğru veriyi verir. Kullanıcı başka bir alanı düzeltene kadar "Şifreler eşleşmiyor." görünmez. Gerekirse when seçeneğiyle refine'ın hangi koşulda çalışacağını kendiniz belirleyin.8
Dönüşüm: transform ve pipe
.transform doğrulanan değeri başka bir değere çevirir. Şemanın girdi ve çıktı tipi artık farklıdır:9
const priceSchema = z
.string()
.regex(/^\d+(,\d{1,2})?$/, "Fiyatı 1250,50 biçiminde girin.")
.transform((value) => Number(value.replace(",", ".")));
type PriceInput = z.input<typeof priceSchema>; // string
type PriceOutput = z.output<typeof priceSchema>; // number.pipe bir şemanın çıktısını ikinci bir şemaya verir. Dönüşümden sonra tekrar doğrulamak için kullanılır:9
const ibanSchema = z
.string()
.transform((digits) => `TR${digits}`)
.pipe(z.iban("IBAN hatalı; numarayı kontrol edin."));Girdi ve çıktı tipinin ayrılması formlarda önemlidir: form girdi tipini tutar, gönderim çıktı tipini alır (bkz. React Hook Form ile Zod).
Boş Alan Tuzakları
Formdan gelen değer çoğu zaman metindir ve boş alan ""'dır, undefined değil. Üç sık hata:
// Boş bırakılabilir URL
website: z.union([z.url("Web sitesini https://ornek.com biçiminde girin."), z.literal("")]),
// Zorunlu sayı: boş metni önce yakalayın
age: z.string().min(1, "Yaşınızı girin.").pipe(z.coerce.number<string>().int().min(18)),z.coerce.number()'ın girdi tipi unknown'dır; şemayı formla kullanırken bu tip useForm'a da yansır. pipe ile bağlarken girdi tipini generic ile verin: z.coerce.number<string>().11
Hatayı Biçimlendirmek
result.error.issues ham listedir. Zod 4 üç yardımcı verir:12
const result = signUpSchema.safeParse(input);
if (!result.success) {
z.flattenError(result.error);
// { formErrors: [], fieldErrors: { email: ["Geçersiz e-posta adresi"] } }
z.treeifyError(result.error); // iç içe nesne ve diziler için
z.prettifyError(result.error); // log için okunur metin
}Düz formlarda z.flattenError yeterlidir; sunucudan alan hatası döndürmek için kullanacaksınız. Zod 3'teki error.flatten() ve error.format() kullanımdan kaldırıldı.12
Yeni Biçimler
Zod 4.5 ve 4.6 formlarda işe yarayan iki biçim ekledi:513
z.creditCard(); // 12-19 hane ve Luhn sağlaması; boşluklu "4111 1111 1111 1111" geçerli
z.iban(); // elektronik biçim: boşluksuz, büyük harf, mod-97 sağlamasıTelefon için z.e164() (+905321234567) hazır gelir.3 Maskeli alanlarda bu biçimleri ham değer üzerinde nasıl kullanacağınız Maskeleme ve regex dersinde.
Kendin Dene
signUpSchema'yı yazıpsafeParse'a{ name: " a", email: "x@", age: "20" }verin. Kaç hata çıkıyor?ageneden hata veriyor?z.config(tr())ekleyip aynı denemeyi yapın.Şifre şemasına
role: z.enum(["buyer", "seller"])ekleyin,role: ""ve farklı şifreler verin. "Şifreler eşleşmiyor." görünüyor mu?z.url().optional()'a""verin, sonraz.literal("")ile birleştirin.priceSchemaiçinz.inputvez.outputtiplerini editörde fareyle inceleyin.
Detaylı Öğrenmek İçin
Resmi doküman: "Basic usage"; şema, parse ve tip çıkarımı.1
Resmi doküman: "Customizing errors";
errorparametresi, öncelik sırası ve dil paketleri.6Resmi doküman: "Migration guide"; Zod 3'ten 4'e değişen API'ler.7
Kaynaklar
Şema tanımlamak, `parse`, `safeParse` ve `z.infer`.
Kurulum ve gereksinimler.
Üst düzey string biçimleri, `z.e164`, `z.creditCard` ve `z.iban`.
Zod 4'teki yenilikler ve üst düzey biçim fonksiyonları.
9 Eylül 2026. `.validate()` ve `z.iban()`.
`error` parametresi ve `z.config` ile dil paketleri.
`message`, `invalid_type_error`, `required_error` ve `flatten`'ın yerini alanlar.
`.refine`, `path`, `abort` ve `when`.
`.transform`, `.pipe`, `z.input` ve `z.output`.
`optional`'ın yalnızca `undefined`'ı kabul etmesi.
`z.coerce` ve girdi tipinin `unknown` olması.
`z.flattenError`, `z.treeifyError` ve `z.prettifyError`.
28 Ağustos 2026. `z.creditCard()` ve diğer yenilikler.
Last updated: October 22, 2026
