12k
All articles

ArkType, eine schnellere Alternative zu Zod

Vergleichen Sie Syntax, Typinferenz, Validierungsgeschwindigkeit und API-Antwortverarbeitung von ArkType und Zod. Erfahren Sie, wann ArkType passt und wann Zod bleibt.

OpenReplay Team
OpenReplay Team
ArkType, eine schnellere Alternative zu Zod

ArkType ist ein TypeScript-Runtime-Validator, der Schemas als TypeScript-ähnliche Strings definiert und sie zu optimierten Validatoren kompiliert. Für ein Team mit einer stabilen Zod-Codebasis lohnt sich eine vollständige Migration selten. Für ein neues Projekt oder einen performancekritischen Validierungspfad ist ein Test jedoch lohnenswert.

Wenn Sie Zod verwenden, haben Sie wahrscheinlich schon das Benchmark-Diagramm von ArkType gesehen und sich gefragt, ob der Geschwindigkeitsvorteil das Erlernen einer neuen Syntax rechtfertigt.

Dieser Artikel überträgt ein einzelnes User-Schema von Zod nach ArkType. Er behandelt Typinferenz, Performance, die Validierung einer API-Antwort und die Abwägungen und sagt anschließend klar, wann Sie besser bei Zod bleiben. Die Beispiele verwenden ArkType 2.2 und Zod 4.

Die wichtigsten Erkenntnisse

  • ArkType definiert Schemas als TypeScript-ähnliche Strings, sodass "'android' | 'ios'" genau wie der erzeugte Union-Typ aussieht, während Zod z.enum(["android", "ios"]) schreibt.
  • Wird ein ArkType-Typ auf unbekannte Daten angewendet, liefert er entweder den validierten Wert oder eine ArkErrors-Instanz zurück. Die idiomatische Prüfung lautet daher out instanceof type.errors.
  • Laut der ArkType-Homepage ist ArkType zur Laufzeit 20-mal schneller als Zod 4. Dabei handelt es sich um eine Angabe des Herstellers selbst, und Zod 4.5 hat inzwischen z.compile() für performancekritische Pfade eingeführt.
  • ArkType 2.2 akzeptiert jeden Standard-Schema-Validator innerhalb von type(), sodass ein bestehendes Zod-4-Schema in eine ArkType-Definition eingebettet werden kann, statt es zuerst neu schreiben zu müssen.

Was ist der Unterschied zwischen ArkType und Zod in einem Satz?

Zod baut ein Schema aus verketteten Methodenaufrufen auf, während ArkType ein Schema als TypeScript-ähnliche Strings schreibt, sodass es sich wie der erzeugte Typ liest. Ein als "(number | string)[]" deklariertes Feld ist genau die TypeScript-Annotation, die Sie ohnehin geschrieben hätten – nur in Anführungszeichen. Der ArkType-Leitfaden „Your First Type“ weist darauf hin, dass Ihr Editor diese String-Definitionen bereits während der Eingabe prüft, inklusive Autovervollständigung, und dabei das Typsystem von TypeScript selbst nutzt.

Dasselbe User-Schema in Zod und ArkType

Nachfolgend sehen Sie dasselbe Schema mit drei Feldern in beiden Bibliotheken: ein Pflicht-String, eine Union aus zwei Werten und ein optionales Array aus Zahlen oder Strings.

Zod 4:

import * as z from "zod"

const User = z.object({
  name: z.string(),
  platform: z.enum(["android", "ios"]),
  versions: z.array(z.union([z.number(), z.string()])).optional(),
})

ArkType 2.2:

import { type } from "arktype"

const User = type({
  name: "string",
  platform: "'android' | 'ios'",
  "versions?": "(number | string)[]",
})

Die ArkType-Version kommt ohne verschachtelte Builder-Aufrufe aus. Auch die Kennzeichnung optionaler Felder verschiebt sich: ArkType markiert – wie TypeScript – den Schlüssel mit ?, während Zod .optional() auf dem Wert aufruft. ArkType unterstützt außerdem eine globale exactOptionalPropertyTypes-Konfiguration (eingeführt in 2.1.12), die der gleichnamigen TypeScript-Compiler-Option entspricht.

KriteriumZod 4ArkType 2.2
Schema-SyntaxVerkettete Builder-MethodenTypeScript-ähnliche Strings und Objektliterale
Optionales Feld.optional() auf dem Wert"key?" auf dem Schlüssel
Statischer Typz.infer<typeof User>typeof User.infer
Unbekannte Daten validierenUser.safeParse(data)User(data)
Fehlerprüfung!result.successout instanceof type.errors
Lesbarer FehlertextAufgebaut aus result.error.issuesout.summary
KompilierungOptional über z.compile() (Zod 4.5+)Fester Bestandteil der Verarbeitung von Definitionen

Typinferenz: typeof User.infer vs. z.infer

Beide Bibliotheken leiten den statischen Typ aus dem Runtime-Schema ab, sodass Sie das Interface nie von Hand schreiben müssen. Lediglich die Syntax zum Extrahieren unterscheidet sich.

// Zod
type User = z.infer<typeof User>

// ArkType
type User = typeof User.infer

In Zod ist z.infer ein generisches Utility, das Sie auf den Typ des Schemas anwenden. In ArkType ist infer eine Eigenschaft des Typs selbst, die über typeof ausgelesen wird. Mit dem obigen Schema ergibt sich in beiden Fällen dieselbe Struktur: { name: string; platform: "android" | "ios"; versions?: (number | string)[] }.

Ist ArkType schneller als Zod?

ArkType erzeugt einen optimierten Validator im Voraus, nämlich beim Erstellen jedes Types. Die ArkType-Konfigurationsdokumentation beschreibt diesen Vorkompilierungsschritt sowie eine Option jitless, mit der er sich deaktivieren lässt. Die ArkType-Homepage gibt an, dass ArkType zur Laufzeit 20-mal schneller als Zod 4 sei. Das ist eine Benchmark-Angabe des Herstellers selbst, keine unabhängige Messung.

Zod 4.5 hat diesen Abstand mit z.compile() inzwischen teilweise verringert. Wie die Zod-Dokumentation zur Kompilierung erläutert, durchläuft z.compile() ein Schema ein einziges Mal und erzeugt eine geradlinige Prüffunktion, die Zod mit new Function() ausführt. Besteht eine Eingabe diese schnelle Prüfung nicht, übergibt Zod sie an den normalen Parser, sodass die detaillierten Fehlermeldungen unverändert bleiben. Die Zod-README nennt eine mediane Beschleunigung um den Faktor 2,4 über einen Benchmark mit 55 Schemas. Ein Vergleich mit unkompiliertem Zod 4 sagt daher nichts darüber aus, wie ArkType gegenüber einem kompilierten Zod-Schema abschneidet.

Bei der Formularvalidierung spielt der Geschwindigkeitsunterschied zwischen ArkType und Zod selten eine Rolle. Ein paar Validierungen pro Nutzerinteraktion werden nicht zu Ihrem Flaschenhals. Relevant wird die Geschwindigkeit, wenn ein Schema tausende Male pro Sekunde ausgeführt wird, etwa in Request-Handlern oder bei Batch-Importen.

Eine API-Antwort durchgängig validieren

Die häufigste Aufgabe in der Praxis besteht darin, eine fetch-Antwort zu prüfen, bevor der Rest der Anwendung ihr vertraut. Hier ist dieselbe Funktion in beiden Bibliotheken.

ArkType:

async function getUser(id: string) {
  const res = await fetch(`/api/users/${id}`)
  const out = User(await res.json())

  if (out instanceof type.errors) {
    console.error(out.summary)
    return null
  }
  return out // typed as User
}

Zod:

async function getUser(id: string) {
  const res = await fetch(`/api/users/${id}`)
  const result = User.safeParse(await res.json())

  if (!result.success) {
    console.error(result.error.issues)
    return null
  }
  return result.data
}

Zod und ArkType liefern bei der Validierung unterschiedliche Strukturen zurück. Zods safeParse gibt ein diskriminiertes Ergebnisobjekt mit success, data und error zurück. Ein ArkType-Typ liefert entweder direkt den validierten Wert oder eine ArkErrors-Instanz. Nach der instanceof-Prüfung verengt TypeScript out auf User. out.summary ist eine einzige lesbare Meldung, die jeden fehlerhaften Pfad auflistet – samt dem dort erwarteten und dem tatsächlich erhaltenen Wert.

ArkErrors lässt sich außerdem direkt an JSON.stringify() übergeben – eine Änderung, die mit ArkType 2.1.10 eingeführt wurde und in den Release Notes zu 2.2 aufgeführt ist. Ein Validierungsfehler kann somit direkt in eine API-Fehlerantwort oder einen Logeintrag einfließen, ohne dass Sie zuerst einen Formatter schreiben müssen.

Die Abwägung: Ökosystem und Vertrautheit vs. eine neue Grammatik

Zods größter Vorteil gegenüber ArkType ist alles, was drumherum existiert. Zod verfügt über ein großes Ökosystem an Integrationen, und die meisten TypeScript-Entwickler können ein Zod-Schema bereits lesen. Ein Teil dieses Vorsprungs schrumpft durch Standard Schema, eine gemeinsame Schnittstelle, die Zod, ArkType und Valibot gleichermaßen implementieren. Prüfen Sie vor einem Wechsel, ob Ihre Formularbibliothek, Ihr Router und Ihre RPC-Schicht Standard Schema unterstützen.

Die Nachteile von ArkType sind real:

  • Eine neue Grammatik. Unions, Arrays und optionale Schlüssel wirken vertraut, aber Constraints und fortgeschrittenere Ausdrücke bilden eine eigene String-Sprache, die Ihr Team erlernen muss.
  • Fehler erscheinen als Typfehler auf Strings. Einen Tippfehler wie "strng" erkennt TypeScript zwar im Editor, allerdings als Fehler in einer String-Definition statt als fehlende Methode. Ihr Team muss sich also an eine neue Art von Fehlermeldungen gewöhnen.

ArkType 2.2 ermöglicht eine schrittweise Einführung. Die ArkType-Dokumentation zu Integrationen zeigt, dass type() jeden Standard-Schema-Validator akzeptiert – eigenständig oder innerhalb einer Objektdefinition – und ihn wie eine native ArkType-Definition inferiert und prüft. Bestehende Zod-4-Schemas können also unverändert bleiben:

import * as z from "zod"
import { type } from "arktype"

const ZodDevice = z.object({ platform: z.enum(["android", "ios"]) })

const User = type({
  name: "string",
  device: ZodDevice, // Standard Schema validator nested in ArkType (2.1.28+)
})

Wenn die Bundle-Größe statt der Geschwindigkeit Ihre wichtigste Einschränkung ist, sollten Sie sich Valibot ansehen.

Wann sollten Sie von Zod zu ArkType wechseln?

Die meisten Teams mit einer stabilen Zod-Codebasis und funktionierenden Integrationen sollten vorerst nicht zu ArkType wechseln. Die Migrationskosten übersteigen einen Geschwindigkeitsgewinn, den der Compiler von Zod 4.5 bereits teilweise abdeckt. Testen Sie ArkType, wenn:

  • Sie ein neues Projekt starten und Ihr Tooling Standard Schema unterstützt.
  • Sie einen nachweislich performancekritischen Pfad haben, etwa einen Endpoint mit hohem Durchsatz oder einen Batch-Job, bei dem das Profiling Validierungskosten aufzeigt.
  • Sie es an einem einzelnen Endpoint ausprobieren möchten, indem Sie bestehende Zod-Schemas in ArkType-Definitionen einbetten, statt sie neu zu schreiben.

Andernfalls sollten Sie weiterhin Daten mit Zod validieren und z.compile() bei den Schemas ausprobieren, die am häufigsten ausgeführt werden.

Fazit

ArkTypes größter Vorteil ist die Lesbarkeit: Das Schema sieht aus wie der Typ, den es erzeugt, und Sie erhalten einen schnellen, kompilierten Validator. Zods Vorteil besteht darin, dass es bereits in Ihren Stack integriert ist. Um den Unterschied mit geringem Aufwand zu testen, wählen Sie einen validierungsintensiven Endpoint, definieren ihn mit ArkType 2.2 unter Einbettung Ihrer bestehenden Zod-Schemas und vergleichen ihn per Profiling mit einer z.compile()-Version desselben Zod-Schemas, bevor Sie irgendetwas anderes ändern.

Häufig gestellte Fragen

Funktioniert ArkType in Cloudflare Workers oder unter einer strikten Content Security Policy?

Ja. ArkType kompiliert die Validierungslogik beim Instanziieren eines Types mit new Function vor und deaktiviert dies automatisch in Umgebungen, die new Function nicht unterstützen, etwa in Cloudflare Workers. Bei einer CSP ohne 'unsafe-eval' setzen Sie die Option jitless auf true. Konfigurieren Sie sie über 'arktype/config', bevor Sie irgendetwas aus 'arktype' importieren, damit die integrierten Keywords die Einstellung übernehmen. Die Validierung funktioniert weiterhin, nur ohne die vorkompilierten Validatoren.

Kann ArkType wie Zod 4 JSON Schema erzeugen?

Ja. Jeder ArkType-Type besitzt eine Methode toJsonSchema(), und ArkType 2.2 hat das Paket @ark/json-schema für die umgekehrte Richtung eingeführt, das JSON Schema in ArkType-Types umwandelt. Features ohne Entsprechung in JSON Schema, etwa Morphs, Symbol-Schlüssel oder Date, führen standardmäßig dazu, dass toJsonSchema() eine Exception wirft. Über eine fallback-Option können Sie jeden dieser Fälle individuell behandeln. Zod 4 deckt denselben Bedarf mit z.toJSONSchema() ab.

Was ist das ArkType-Pendant zu Zods transform()?

ArkType bezeichnet Transformationen als Morphs und hängt sie mit .pipe() an, zum Beispiel type('string').pipe(s => s.trim()). Integrierte Parse-Keywords wie 'string.json.parse' und 'string.numeric.parse' erledigen gängige Konvertierungen ohne Callback. Wirft ein Morph eine Exception, geht ArkType davon aus, dass ein Absturz beabsichtigt ist. Verwenden Sie stattdessen .pipe.try(), um die geworfene Exception in ein ArkErrors-Ergebnis umzuwandeln. Der inferierte Typ spiegelt die Ausgabe des Morphs wider.

Kann ArkType bei ungültigen Daten wie Zods parse() eine Exception werfen, statt Fehler zurückzugeben?

Ja. Der Aufruf von out.throw() auf einem ArkErrors-Ergebnis wirft dieses, und die globale Option onFail sorgt dafür, dass jeder Type bei ungültigen Daten eine Exception wirft: configure({ onFail: errors => errors.throw() }) aus 'arktype/config'. Deklarieren Sie dasselbe onFail im globalen ArkEnv-Interface, damit TypeScript weiß, dass Aufrufe kein ArkErrors mehr zurückgeben. Der standardmäßige Rückgabewert-Stil entspricht Zods safeParse(), onFail entspricht parse().

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.