deepkit/type pour TypeScript : guide complet avec exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

deepkit/type pour TypeScript : guide complet avec exemples

Dans le monde de TypeScript, il existe un problème fondamental : les types n'existent que lors de la compilation. Après la transpilation en JavaScript, toutes les informations de type disparaissent. Cela rend impossible la validation à l'exécution, la sérialisation dynamique ou la construction de systèmes complexes dépendant des métadonnées de type. La bibliothèque deepkit/type résout ce problème de manière radicale : elle transporte le système de types TypeScript dans l'exécution, permettant de travailler avec les types comme avec des données.

La valeur principale de deepkit/type réside dans le fait qu'elle ne nécessite pas d'écrire des schémas redondants (comme dans Zod ou Yup). Vous décrivez les types une seule fois — en TypeScript pur — et la bibliothèque les extrait automatiquement à l'exécution. Cela permet d'effectuer la validation des données, la sérialisation/désérialisation, la réflexion (obtention d'informations sur les propriétés, les génériques, les décorateurs) et même de générer du code basé sur les types. deepkit/type n'est pas simplement un validateur, c'est un framework complet pour la métaprogrammation.

La bibliothèque est idéale pour les projets où une typage strict est essentiel à tous les niveaux : serveurs API (validation des requêtes entrantes), bases de données (mappage de types en SQL), fichiers de configuration, systèmes RPC et outils de génération de code. Grâce à son intégration avec deepkit/framework, elle est également utilisée pour créer des applications serveur haute performance avec validation et sérialisation automatiques.

Installation

deepkit/type est un package npm pour TypeScript. L'installation se fait avec la commande standard :

npm install @deepkit/type reflect-metadata

Vous devrez également configurer tsconfig.json pour prendre en charge les décorateurs et l'émission de métadonnées :

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true,
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist"
  }
}

Si vous utilisez ts-node pour l'exécution, assurez-vous qu'il charge reflect-metadata en premier. Ajoutez au début de votre fichier d'entrée :

import 'reflect-metadata';

Démarrage rapide

Un exemple minimal montre comment déclarer un type et obtenir sa représentation à l'exécution :

import 'reflect-metadata';
import { typeOf, ReflectionClass } from '@deepkit/type';

// Déclaration de l'interface
interface User {
  id: number;
  name: string;
  email?: string;
}

// Obtention du type à l'exécution
const userType = typeOf();
console.log(userType); // ReflectionClass

// Vérification des propriétés
const reflection = ReflectionClass.from(userType);
console.log(reflection.getProperty('name').type); // ReflectionProperty
console.log(reflection.getProperty('id').type.kind); // 'number'

Ce code affichera les informations sur le type User dans la console. Notez que nous n'avons écrit aucun schéma — seulement une interface TypeScript pure.

Méthodes et fonctions principales

Voici les fonctionnalités clés de deepkit/type. Pour chaque méthode, la signature, une brève description et un exemple fonctionnel sont fournis.

1. typeOf

Signature : typeOf<T>(): ReflectionClass

Ce qu'elle fait : Extrait la représentation à l'exécution du type T. Retourne un objet ReflectionClass contenant toutes les informations sur la structure du type : propriétés, leurs types, modificateurs (optional, readonly), génériques et décorateurs.

import { typeOf } from '@deepkit/type';

interface Product {
  id: number;
  title: string;
  price: number;
}

const productType = typeOf();
console.log(productType.getProperty('title').type.kind); // 'string'
console.log(productType.getProperty('price').type.kind); // 'number'

2. is

Signature : is<T>(value: unknown): value is T

Ce qu'elle fait : Vérifie si une valeur correspond au type T à l'exécution. Fonctionne comme un prédicat de type TypeScript, ce qui permet une inférence de type automatique après la vérification.

import { is } from '@deepkit/type';

interface User {
  id: number;
  name: string;
}

const data: unknown = { id: 1, name: 'Alice' };

if (is(data)) {
  // TypeScript sait maintenant que data est de type User
  console.log(data.name.toUpperCase()); // 'ALICE'
}

3. cast

Signature : cast<T>(value: unknown): T

Ce qu'elle fait : Convertit une valeur en un type T, en effectuant les transformations nécessaires (par exemple, conversion de chaînes en nombres, application de valeurs par défaut). Contrairement à is, cast ne lève pas d'erreur mais tente de transformer la valeur pour qu'elle corresponde au type.

import { cast } from '@deepkit/type';

interface Config {
  port: number;
  host: string;
}

const raw = { port: '3000', host: 'localhost' };
const config = cast(raw);
console.log(config.port); // 3000 (nombre, pas une chaîne)

4. serialize

Signature : serialize<T>(value: T): any

Ce qu'elle fait : Convertit une valeur typée en un objet JSON simple, en supprimant les propriétés non définies dans le type et en appliquant les transformations de sérialisation (comme la conversion de dates en chaînes).

import { serialize } from '@deepkit/type';

interface User {
  id: number;
  name: string;
  createdAt: Date;
}

const user: User = { id: 1, name: 'Bob', createdAt: new Date() };
const json = serialize(user);
console.log(json); // { id: 1, name: 'Bob', createdAt: '2024-01-15T10:30:00.000Z' }

5. deserialize

Signature : deserialize<T>(value: any): T

Ce qu'elle fait : Convertit un objet JSON simple en une instance typée T, en restaurant les types complexes (comme les dates, les tableaux typés, etc.).

import { deserialize } from '@deepkit/type';

interface User {
  id: number;
  name: string;
  createdAt: Date;
}

const json = { id: 1, name: 'Bob', createdAt: '2024-01-15T10:30:00.000Z' };
const user = deserialize(json);
console.log(user.createdAt instanceof Date); // true

6. ReflectionClass

Signature : ReflectionClass.from(type: ReflectionClass): ReflectionClass

Ce qu'elle fait : Fournit une API complète pour inspecter la structure d'un type : lister les propriétés, leurs types, les décorateurs, les génériques, et même les méthodes. C'est la classe centrale pour la réflexion avancée.

import { typeOf, ReflectionClass } from '@deepkit/type';

interface Product {
  id: number;
  title: string;
  price: number;
  tags?: string[];
}

const productType = typeOf();
const reflection = ReflectionClass.from(productType);

// Liste des propriétés
reflection.getProperties().forEach(prop => {
  console.log(`${prop.name}: ${prop.type.kind} (optional: ${prop.optional})`);
});
// Affiche :
// id: number (optional: false)
// title: string (optional: false)
// price: number (optional: false)
// tags: array (optional: true)

Cas d'utilisation avancés

Validation de requêtes API

deepkit/type excelle dans la validation des données entrantes d'une API REST :

import { is, cast } from '@deepkit/type';

interface CreateUserRequest {
  name: string;
  email: string;
  age: number;
}

app.post('/users', (req, res) => {
  const body = req.body;
  
  if (!is(body)) {
    return res.status(400).json({ error: 'Données invalides' });
  }
  
  const user = cast(body);
  // user est maintenant typé et validé
  createUser(user);
});

Génération de schémas OpenAPI

Grâce à la réflexion, vous pouvez générer automatiquement des schémas OpenAPI à partir de vos types TypeScript :

import { typeOf, ReflectionClass } from '@deepkit/type';

interface User {
  id: number;
  name: string;
  email: string;
}

function generateOpenApiSchema(): object {
  const reflection = ReflectionClass.from(typeOf());
  const properties: Record = {};
  
  reflection.getProperties().forEach(prop => {
    properties[prop.name] = { type: prop.type.kind };
  });
  
  return {
    type: 'object',
    properties,
    required: reflection.getProperties()
      .filter(p => !p.optional)
      .map(p => p.name)
  };
}

const userSchema = generateOpenApiSchema();
console.log(JSON.stringify(userSchema, null, 2));

Conclusion

deepkit/type transforme la façon dont les développeurs TypeScript abordent la validation, la sérialisation et la réflexion. En éliminant le besoin de schémas redondants, elle réduit la duplication de code et améliore la maintenabilité. Que vous construisiez une API, un ORM ou un outil de génération de code, deepkit/type offre une solution élégante et performante pour travailler avec les types à l'exécution.

Recommendations