ArkType ile Runtime Type Validation: TypeScript Syntax'ını Runtime'a Taşıyın
TypeScript geliştiricileri olarak hepimiz aynı sorunu yaşıyoruz: compile-time'da mükemmel tip güvenliğine sahipken, runtime'da API'den gelen veriler, kullanıcı girdileri veya harici kaynaklardan okunan datalar karşısında tamamen savunmasız kalıyoruz. Bu boşluğu doldurmak için Zod, Yup, io-ts gibi kütüphaneler ortaya çıktı. Ancak bu kütüphanelerin hepsinde ortak bir sorun var: kendi özel syntax'larını öğrenmeniz gerekiyor.
Peki ya runtime validation şemalarınızı doğrudan TypeScript syntax'ı ile yazabilseydiniz? İşte tam olarak ArkType'ın sunduğu devrimsel yaklaşım bu.
ArkType Nedir?
ArkType, TypeScript'in tip syntax'ını runtime'da çalıştırabilen bir validation kütüphanesidir. 2024 yılında 2.0 sürümüyle olgunlaşan bu araç, string tabanlı type expression'lar kullanarak TypeScript yazıyormuş hissini runtime validation'a taşır.
ArkType'ın temel felsefesi şudur: Zaten TypeScript biliyorsanız, yeni bir DSL öğrenmenize gerek yok.
ArkType'ın Öne Çıkan Özellikleri
- TypeScript-native syntax: Tip tanımları, TypeScript'teki yazımla neredeyse birebir aynı
- Blazing fast performance: Zod'dan 100 kata kadar daha hızlı çalışabilir
- Tam type inference: Tanımladığınız şemalardan otomatik TypeScript tipleri türetilir
- Küçük bundle size: Tree-shaking dostu, minimal overhead
- Detaylı hata mesajları: Geliştirici deneyimini artıran anlaşılır error output'ları
Kurulum ve İlk Adımlar
ArkType'ı projenize eklemek son derece basit:
npm install arktypeİlk type tanımımızı oluşturalım:
import { type } from "arktype";
// TypeScript syntax'ına ne kadar benzediğine dikkat edin
const user = type({
name: "string",
email: "string.email",
age: "number",
});
// Type inference otomatik olarak çalışır
type User = typeof user.infer;
// { name: string; email: string; age: number }
// Validation
const result = user({
name: "Ahmet",
email: "ahmet@example.com",
age: 28,
});
if (result instanceof type.errors) {
console.error(result.summary);
} else {
console.log(result); // Tip güvenli data
}Gördüğünüz gibi, "string", "number" gibi ifadeler doğrudan TypeScript'in primitive tiplerini yansıtıyor. Zod'daki z.string(), z.number() gibi method chain'lere kıyasla çok daha doğal bir yazım sunuyor.
Temel Tip Tanımları
Primitive Tipler
import { type } from "arktype";
const primitives = type({
name: "string",
age: "number",
isActive: "boolean",
createdAt: "Date",
id: "string | number", // Union type - tıpkı TypeScript gibi!
metadata: "unknown",
callback: "Function",
});String Validation'ları
ArkType, string tipine özel validation'lar için güçlü alt-tipler sunar:
const contactForm = type({
email: "string.email",
website: "string.url",
phone: "string.regex",
uuid: "string.uuid",
ip: "string.ip",
});Sayısal Kısıtlamalar
TypeScript'e benzer ama runtime'da çalışan sayısal constraint'ler:
const product = type({
name: "string > 0", // En az 1 karakter
price: "number > 0", // Pozitif sayı
quantity: "number.integer >= 0", // Negatif olmayan tam sayı
discount: "0 <= number <= 100", // 0-100 arası
rating: "1 <= number <= 5", // 1-5 arası rating
});
const result = product({
name: "Laptop",
price: 15999.99,
quantity: 50,
discount: 15,
rating: 4.5,
});Bu sözdizimi gerçekten etkileyici — "0 <= number <= 100" ifadesi matematiksel notasyona ne kadar yakın değil mi?
İleri Düzey Kullanım
Array ve Tuple Tipleri
const config = type({
tags: "string[]", // String dizisi
scores: "number[]", // Sayı dizisi
matrix: "number[][]", // İç içe dizi
pair: ["string", "number"], // Tuple: [string, number]
coordinates: ["number", "number", "number"], // 3D koordinat
});Optional ve Default Değerler
const userProfile = type({
name: "string",
"email?": "string.email", // Optional field
age: "number = 18", // Default değer
"bio?": "string",
role: "'user' | 'admin' = 'user'", // Literal union + default
});
const result = userProfile({
name: "Zeynep",
});
// { name: "Zeynep", age: 18, role: "user" }Nested (İç İçe) Objeler
const blogPost = type({
title: "string > 0",
content: "string",
author: {
name: "string",
email: "string.email",
"avatar?": "string.url",
},
tags: "string[]",
metadata: {
publishedAt: "Date",
"updatedAt?": "Date",
views: "number.integer >= 0",
},
});
type BlogPost = typeof blogPost.infer;Union ve Intersection Tipleri
// Discriminated union - TypeScript'teki gibi
const shape = type({
kind: "'circle'",
radius: "number > 0",
}).or({
kind: "'rectangle'",
width: "number > 0",
height: "number > 0",
});
// Intersection ile tip birleştirme
const timestamped = type({
createdAt: "Date",
updatedAt: "Date",
});
const baseEntity = type({
id: "string.uuid",
name: "string",
});
const entity = baseEntity.and(timestamped);
type Entity = typeof entity.infer;
// { id: string; name: string; createdAt: Date; updatedAt: Date }Zod ile Karşılaştırma
ArkType'ın değerini tam olarak anlamak için, aynı şemayı hem Zod hem de ArkType ile yazalım:
Zod ile:
import { z } from "zod";
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().min(0).max(150),
role: z.enum(["user", "admin"]).default("user"),
address: z.object({
street: z.string(),
city: z.string(),
zipCode: z.string().regex(/^\d{5}$/),
}).optional(),
hobbies: z.array(z.string()).min(1),
});
type User = z.infer<typeof UserSchema>;ArkType ile:
import { type } from "arktype";
const User = type({
name: "string > 0",
email: "string.email",
age: "0 <= number.integer <= 150",
role: "'user' | 'admin' = 'user'",
"address?": {
street: "string",
city: "string",
zipCode: "string.regex",
},
hobbies: "string[] > 0",
});
type User = typeof User.infer;Fark açıkça görülüyor: ArkType versiyonu daha kısa, daha okunabilir ve TypeScript'e çok daha yakın.
Performans Karşılaştırması
ArkType'ın en büyük avantajlarından biri performans. Benchmark sonuçlarına göre:
| Kütüphane | Saniyedeki İşlem (ops/sec) | Bundle Size |
|---|---|---|
| ArkType | ~10,000,000 | ~30KB |
| Zod | ~100,000 | ~57KB |
| Yup | ~50,000 | ~75KB |
ArkType, tip tanımlarını derleme aşamasında optimize ettiği için runtime'da çok daha hızlı çalışır. Bu, özellikle yüksek throughput gerektiren API endpoint'lerinde kritik bir avantajdır.
Gerçek Dünya Örneği: Express API Validation
ArkType'ı bir Express.js API'sinde nasıl kullanacağınızı görelim:
import express from "express";
import { type } from "arktype";
const app = express();
app.use(express.json());
// Request body şeması
const CreateOrderBody = type({
customerId: "string.uuid",
items: [{
productId: "string.uuid",
quantity: "number.integer > 0",
"note?": "string",
}, "[]"], // Array of objects
"couponCode?": "string",
shippingAddress: {
line1: "string > 0",
"line2?": "string",
city: "string > 0",
state: "string > 0",
zipCode: "string",
country: "string == 2", // Tam 2 karakter (ülke kodu)
},
});
// Generic validation middleware
function validate<T>(schema: type.Any) {
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
const result = schema(req.body);
if (result instanceof type.errors) {
return res.status(400).json({
error: "Validation failed",
details: result.summary,
});
}
req.body = result; // Validated ve parsed data
next();
};
}
app.post("/api/orders", validate(CreateOrderBody), (req, res) => {
// req.body artık tip güvenli
const order = req.body;
console.log(order.customerId); // string - tip güvenli!
res.json({ success: true, order });
});Morph (Dönüşüm) Özelliği
ArkType sadece validation yapmaz, veriyi dönüştürme (transform) yeteneğine de sahiptir:
import { type } from "arktype";
// String'den number'a dönüşüm
const numericString = type("string.numeric.parse");
const result = numericString("42");
// result: 42 (number tipinde)
// Tarih parse etme
const dateString = type("string.date.parse");
const date = dateString("2024-01-15");
// date: Date objesi
// Özel dönüşümler ile
const percentage = type("string")
.pipe((s) => parseFloat(s))
.pipe(type("0 <= number <= 100"));
const val = percentage("85.5");
// val: 85.5 (validated number)Hata Yönetimi
ArkType'ın hata mesajları son derece okunabilirdir:
const user = type({
name: "string > 0",
email: "string.email",
age: "0 <= number.integer <= 150",
});
const result = user({
name: "",
email: "invalid-email",
age: -5,
});
if (result instanceof type.errors) {
console.log(result.summary);
// name must be more than 0 characters (was 0)
// email must be an email address (was "invalid-email")
// age must be at least 0 (was -5)
}ArkType Ne Zaman Tercih Edilmeli?
ArkType'ı seçmeniz gereken durumlar:
- Performans kritik uygulamalar: Yüksek throughput gerektiren API'ler
- TypeScript ekipleri: Ekip zaten TypeScript'e hakimse, öğrenme eğrisi minimum olur
- Okunabilirlik öncelikli projeler: Şema tanımlarının kolayca anlaşılması gerektiğinde
- Bundle size hassasiyeti: Frontend uygulamalarında her KB önemli olduğunda
Zod'u tercih etmeniz gereken durumlar:
- Olgun ekosistem gereksinimi: tRPC, React Hook Form gibi entegrasyonlar
- Geniş topluluk desteği: Daha fazla Stack Overflow cevabı, blog yazısı
- Karmaşık custom validation'lar:
.refine()ve.superRefine()ile esnek kurallar
Sonuç
ArkType, TypeScript dünyasında runtime validation yaklaşımını yeniden tanımlayan cesur bir kütüphane. "TypeScript biliyorsan, ArkType'ı da biliyorsun" mottosu gerçekten karşılığını buluyor. String-based type expression'lar sayesinde şema tanımları hem kısa hem de son derece okunabilir oluyor.
Performans konusundaki üstünlüğü, TypeScript-native syntax'ı ve küçük bundle size'ı ile ArkType, özellikle 2024-2025 döneminde Zod'a ciddi bir alternatif olarak yükseliyor. Eğer yeni bir proje başlıyorsanız veya mevcut validation katmanınızı modernize etmek istiyorsanız, ArkType'a mutlaka bir şans verin.
Unutmayın: En iyi validation kütüphanesi, ekibinizin en verimli kullandığı kütüphanedir. ArkType'ın TypeScript'e yakın doğası, birçok ekip için bu verimi doğal olarak artıracaktır.