Service en ligne 100% Gratuit Utilitaires Web AngularForAll

- Convertisseur Interface TS → Zod Schema

Convert Ts → Zod Typescript Interface Zod Validation Generer Schema Zod Depuis Interface Ts Zod Typescript Infer Type Automatique Validation Runtime Typescript Angular React

Convertissez vos interfaces TypeScript en schémas Zod instantanément. Génération automatique du code de validation avec types inférés, optionnels, unions, imbriqués et Record.

Convertisseur Interface TypeScript → Zod Schema

Exemple :
TS
ZOD

Qu'est-ce que Zod et pourquoi l'adopter

Pour qui : Développeurs TypeScript, équipes Angular / React, architectes frontend, ingénieurs backend Node.js.

Zod est une bibliothèque de validation de schémas TypeScript-first. Contrairement à Yup ou Joi, Zod infère automatiquement le type TypeScript depuis le schéma — vous n'écrivez plus jamais deux fois la même structure.

  • Zero dépendances — 8 Ko minifié+gzippé
  • TypeScript natifz.infer<typeof MySchema> remplace votre interface
  • Validation runtime — Validez les données à la frontière (API, formulaire, localStorage)
  • Messages d'erreur personnalisables — Retours utilisateur précis sans effort
  • Composable.optional(), .nullable(), .refine(), .transform()
Règle d'or : Si vous avez déjà une interface TypeScript pour votre modèle de données, ce convertisseur génère le schéma Zod équivalent en une seconde — sans risque d'incohérence entre le type statique et la validation runtime.

Pourquoi ne pas garder uniquement les interfaces TypeScript ?

Les types TypeScript sont effacés à la compilation — ils n'existent pas à l'exécution. Une réponse API non conforme passera votre compilateur mais plantera votre application. Zod résout ce problème :

// Sans Zod — le compilateur est aveugle aux erreurs runtime
const user: User = await fetch('/api/user').then(r => r.json());
// user.age pourrait être une string, null, ou absent → crash silencieux

// Avec Zod — validation stricte à la frontière
const user = UserSchema.parse(await fetch('/api/user').then(r => r.json()));
// Si l'API retourne un champ invalide → ZodError immédiat, lisible

Comparaison Zod vs alternatives

Bibliothèque TypeScript natif Inférence de type Taille Popularité (2025)
Zod✔ Oui✔ Automatique8 Ko⭐ 35 M dl/sem
YupPartielManuelle14 Ko18 M dl/sem
JoiVia @typesManuelle45 Ko12 M dl/sem
class-validatorDécorateursManuelle20 Ko8 M dl/sem

Comment utiliser ce convertisseur

Le convertisseur analyse votre interface TypeScript et génère le schéma Zod correspondant avec les bonnes méthodes de validation.

  1. Collez votre interface dans la zone de gauche (ou cliquez sur un exemple)
  2. Ajustez les options :
    • export const : Préfixe export sur chaque schéma
    • z.infer<> : Génère le type inféré type User = z.infer<typeof UserSchema>
    • .strict() : Rejette les clés inconnues (recommandé pour les APIs)
    • Commentaires : Ajoute le type TypeScript original en commentaire
  3. Cliquez "Convertir" ou modifiez le texte (conversion auto après 30 caractères)
  4. Copiez le résultat et collez-le dans votre projet

Interfaces multiples et imbriquées

Si vous collez plusieurs interfaces à la fois, chaque interface génère son propre schéma. Les références entre interfaces sont détectées automatiquement :

// Entrée TypeScript
export interface Address {
  street: string;
  city: string;
}

export interface User {
  id: number;
  address: Address; // ← référence détectée
}

// Schéma Zod généré
export const AddressSchema = z.object({
  street: z.string(),
  city: z.string(),
});
export type Address = z.infer<typeof AddressSchema>;

export const UserSchema = z.object({
  id: z.number(),
  address: AddressSchema, // ← référence résolue
});
export type User = z.infer<typeof UserSchema>;
Conseil : Collez vos interfaces dans l'ordre où elles sont déclarées (les dépendances avant les consommateurs) pour que les références se résolvent correctement.

Mapping des types TypeScript vers Zod

Le convertisseur gère tous les types courants de TypeScript. Voici la table de correspondance complète :

TypeScript Zod généré Notes
stringz.string()Texte quelconque
numberz.number()Entier ou float
booleanz.boolean()true / false
Datez.date()Objet Date JS
anyz.any()Pas de validation
unknownz.unknown()Type inconnu sûr
nullz.null()Valeur null explicite
undefinedz.undefined()Valeur undefined
neverz.never()Type impossible
string[]z.array(z.string())Tableau de strings
Array<number>z.array(z.number())Syntaxe générique
string | nullz.string().nullable()Union avec null
number? (champ optionnel)z.number().optional()Optionnel via ?
string | numberz.union([z.string(), z.number()])Union arbitraire
Record<string, T>z.record(z.string(), z.T())Dictionnaire
[string, number]z.tuple([z.string(), z.number()])Tuple typé
'admin' | 'user'z.union([z.literal('admin'), z.literal('user')])Union de littéraux
Partial<T>TSchema.partial()Tous champs optionnels
Promise<T>z.promise(TSchema)Promise validée
A & Bz.intersection(ASchema, BSchema)Intersection

Gestion des énumérations TypeScript

Les enum TypeScript ne sont pas des interfaces — utilisez z.enum() ou z.nativeEnum() manuellement :

// TypeScript enum
enum Role { Admin = 'ADMIN', User = 'USER', Guest = 'GUEST' }

// Option 1 : z.enum (valeurs string uniquement)
const RoleSchema = z.enum(['ADMIN', 'USER', 'GUEST']);
type Role = z.infer<typeof RoleSchema>; // 'ADMIN' | 'USER' | 'GUEST'

// Option 2 : z.nativeEnum (enum TypeScript natif)
const RoleSchema = z.nativeEnum(Role);
type RoleType = z.infer<typeof RoleSchema>; // Role enum

Validation avancée : refinements et transforms

Après conversion, vous pouvez enrichir votre schéma Zod avec des validations métier que TypeScript ne peut pas exprimer nativement.

Refinements — valider au-delà des types

// Schéma généré par le convertisseur
export const UserSchema = z.object({
  id: z.number(),
  email: z.string(),
  age: z.number().optional(),
});

// Enrichissement manuel après conversion
export const UserSchema = z.object({
  id: z.number().int().positive(),          // entier positif
  email: z.string().email(),                // format email validé
  age: z.number().min(0).max(150).optional(), // plage de valeurs
  username: z.string().min(3).max(20)
    .regex(/^[a-z0-9_]+$/, 'Lettres minuscules, chiffres et _ uniquement'),
  password: z.string().min(8).refine(
    (pw) => /[A-Z]/.test(pw),
    'Le mot de passe doit contenir au moins une majuscule'
  ),
});

Transforms — normaliser les données à la validation

// Trim et lowercase automatiques
const EmailSchema = z.string()
  .trim()
  .toLowerCase()
  .email();

// Convertir string ISO en Date
const DateStringSchema = z.string()
  .datetime()
  .transform((val) => new Date(val));

// Coerce — forcer la conversion de type
const IdSchema = z.coerce.number(); // accepte "42" → 42

Validation conditionnelle avec superRefine

const CheckoutSchema = z.object({
  paymentMethod: z.enum(['card', 'paypal', 'bank']),
  cardNumber: z.string().optional(),
  iban: z.string().optional(),
}).superRefine((data, ctx) => {
  if (data.paymentMethod === 'card' && !data.cardNumber) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: 'Le numéro de carte est requis',
      path: ['cardNumber'],
    });
  }
  if (data.paymentMethod === 'bank' && !data.iban) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "L'IBAN est requis pour un virement",
      path: ['iban'],
    });
  }
});

parse vs safeParse

// parse — lève ZodError si invalide
try {
  const user = UserSchema.parse(rawData);
} catch (e) {
  if (e instanceof z.ZodError) console.log(e.errors);
}

// safeParse — retourne { success, data } ou { success, error }
const result = UserSchema.safeParse(rawData);
if (!result.success) {
  // result.error.errors → tableau d'erreurs avec path et message
  result.error.errors.forEach(err => console.log(err.path, err.message));
} else {
  // result.data est typé correctement
  processUser(result.data);
}

Intégration React Hook Form et Angular

React Hook Form + Zod (zodResolver)

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

// 1. Définir le schéma (généré par notre outil)
const LoginSchema = z.object({
  email: z.string().email('Email invalide'),
  password: z.string().min(8, '8 caractères minimum'),
});

type LoginForm = z.infer<typeof LoginSchema>;

// 2. Utiliser dans le formulaire
function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<LoginForm>({
    resolver: zodResolver(LoginSchema),
  });

  const onSubmit = (data: LoginForm) => {
    // data est typé et validé
    console.log(data.email, data.password);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} />
      {errors.email && <p>{errors.email.message}</p>}
      <input type="password" {...register('password')} />
      {errors.password && <p>{errors.password.message}</p>}
      <button type="submit">Connexion</button>
    </form>
  );
}

Angular Reactive Forms + Zod

// schema.ts (généré par le convertisseur)
import { z } from 'zod';

export const UserFormSchema = z.object({
  name:  z.string().min(2).max(50),
  email: z.string().email(),
  age:   z.number().min(18).optional(),
});

export type UserFormData = z.infer<typeof UserFormSchema>;

// user-form.component.ts
import { Component } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { UserFormSchema, UserFormData } from './schema';

@Component({
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <input formControlName="name" />
      <input formControlName="email" />
      <button type="submit">Envoyer</button>
    </form>
  `
})
export class UserFormComponent {
  form = this.fb.group({
    name:  [''],
    email: [''],
    age:   [null as number | null],
  });

  constructor(private fb: FormBuilder) {}

  onSubmit() {
    const result = UserFormSchema.safeParse(this.form.value);
    if (!result.success) {
      // Afficher les erreurs Zod dans le template
      result.error.errors.forEach(e => console.error(e.path, e.message));
      return;
    }
    // result.data est typé UserFormData
    this.submitToApi(result.data);
  }

  private submitToApi(data: UserFormData) {
    // data.name, data.email sont validés et typés
  }
}

Validation de réponse API dans Angular HttpClient

// api.service.ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { UserSchema } from './schema';

@Injectable({ providedIn: 'root' })
export class ApiService {
  private http = inject(HttpClient);

  getUser(id: number) {
    return this.http.get(`/api/users/${id}`).pipe(
      map(raw => UserSchema.parse(raw)),   // valide + type au runtime
      catchError(err => {
        if (err.name === 'ZodError') {
          console.error('Réponse API invalide:', err.errors);
        }
        return throwError(() => err);
      })
    );
  }
}

FAQ — Questions fréquentes

Le convertisseur gère-t-il les génériques TypeScript comme Response<T> ?

Les paramètres de type génériques (<T>) sont ignorés à la conversion car Zod utilise une approche compositionnelle. Créez un helper :

// Au lieu de Response<T> TypeScript :
const responseSchema = <T extends z.ZodTypeAny>(dataSchema: T) =>
  z.object({
    data: dataSchema,
    status: z.number(),
    message: z.string().optional(),
  });

// Utilisation :
const UserResponseSchema = responseSchema(UserSchema);
type UserResponse = z.infer<typeof UserResponseSchema>;

Comment installer Zod dans mon projet ?

npm install zod
# ou
yarn add zod
# ou
pnpm add zod

Zod est compatible Node.js 12+, navigateurs modernes, Deno, et Bun. Aucune configuration supplémentaire requise.

Quelle est la différence entre .nullable() et .optional() ?

MéthodeValeurs acceptéesTypeScript équivalent
z.string()string uniquementstring
z.string().nullable()string ou nullstring | null
z.string().optional()string ou undefinedstring | undefined (champ optionnel)
z.string().nullish()string, null ou undefinedstring | null | undefined

Peut-on utiliser Zod côté serveur Node.js / NestJS ?

Oui. Dans NestJS, la bibliothèque nestjs-zod intègre Zod avec les DTOs et les pipes de validation. Exemple :

import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';

const CreateUserSchema = z.object({
  name:  z.string().min(2),
  email: z.string().email(),
  role:  z.enum(['admin', 'user']).default('user'),
});

export class CreateUserDto extends createZodDto(CreateUserSchema) {}

// Dans le controller
@Post()
create(@Body() dto: CreateUserDto) {
  // dto est automatiquement validé et typé
}

Comment afficher les erreurs Zod en français ?

import { z } from 'zod';
import { zodI18nMap } from 'zod-i18n-map';
import translation from 'zod-i18n-map/locales/fr/zod.json';
import i18next from 'i18next';

await i18next.init({ lng: 'fr', resources: { fr: { zod: translation } } });
z.setErrorMap(zodI18nMap);

// Maintenant les erreurs Zod sont en français
const result = z.string().email().safeParse('invalide');
// result.error.errors[0].message → "E-mail invalide"

Zod v3 vs v4 — quelles différences ?

Zod v4 (sorti en 2025) apporte des améliorations majeures de performance (5× plus rapide sur les schemas complexes), une meilleure gestion des messages d'erreur, et le support de z.object().merge() plus robuste. Ce convertisseur génère du code compatible avec Zod v3 et v4.

Conclusion

Convertir vos interfaces TypeScript en schémas Zod est l'une des meilleures décisions pour la qualité de votre code frontend. Vous obtenez :

  • Validation runtime à la frontière (API, formulaires, localStorage)
  • Types TypeScript inférés automatiquement — plus de duplication
  • Messages d'erreur précis et personnalisables
  • Compatibilité universelle (Angular, React, Vue, Node.js, Deno)
  • Transformations et normalisations intégrées au schéma

Utilisez ce convertisseur comme point de départ, puis enrichissez vos schémas avec .min(), .max(), .email(), .refine() pour des validations métier précises. Votre code sera plus robuste, plus maintenable et vos bugs de production seront détectés avant même d'atteindre l'utilisateur.

Partager