6 points par honglu 2025-01-08 | 2 commentaires | Partager sur WhatsApp

« Créons une bibliothèque type-safe qui corresponde à mes goûts » : c’est avec cet état d’esprit que ce projet a commencé.

Ce projet a démarré avec une implémentation type-safe de JSON Schema, puis s’est naturellement étendu à divers outils nécessaires au processus de développement.

J’y ai pour l’instant mis un premier point d’arrêt dans le cadre de ma recherche d’emploi.

Principes du projet

Le développement a été mené en respectant les principes fondamentaux suivants :

  • utilisation d’un système de types strict
  • maintien d’un minimum de dépendances externes
  • conception d’un système de types réutilisable
  • documentation de l’API
  • maintien d’une couverture de tests élevée
  • implémentation en TypeScript pur

Bibliothèques

@imhonglu/json-schema

Implémentation TypeScript conforme à la spécification JSON Schema draft 2020-12.

[IMG] demo-1

import { Schema, SchemaDefinition } from "@imhonglu/json-schema";  
  
export const Address = new Schema({  
  type: "object",  
  properties: {  
    street: { type: "string" },  
    city: { type: "string" },  
    zip: { type: "string" },  
  },  
  required: ["street"] as const,  
});  
  
export type Address = SchemaDefinition.Instance<typeof Address>;  
// {  
//   street: string;  
//   city?: string;  
//   zip?: string;  
// }  

@imhonglu/format

Projet lancé pour implémenter le mot-clé format de JSON Schema.

import { FullTime } from '@imhonglu/format';  
  
const time = FullTime.parse('00:00:00.000Z');  
// { hour: 0, minute: 0, second: 0, secfrac: '.000', offset: undefined }  
  
console.log(time.toString()); // '00:00:00.000Z'  
console.log(JSON.stringify(time)); // '"00:00:00.000Z"'  
  
const result = FullTime.safeParse('invalid');  
if (!result.ok) {  
  console.error(result.error);  
}  

@imhonglu/pattern-builder

Un builder regex créé pour améliorer la lisibilité des expressions régulières lors de l’implémentation de la grammaire ABNF des spécifications RFC.

import { characterSet, concat, hexDigit } from "@imhonglu/pattern-builder";  
  
// pct-encoded = "%" HEXDIG HEXDIG  
export const pctEncoded = concat(  
  "%",  
  hexDigit.clone().exact(2),  
);  
  
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"  
export const unreserved = characterSet(  
  alpha,  
  digit,  
  /[\-._~]/,  
);  

@imhonglu/type-guard

Bibliothèque de type guards créée pour améliorer la lisibilité des garde-types.

import { composeGuards } from "@imhonglu/type-guard";  
  
const is = composeGuards({  
  string: (value: unknown): value is string => typeof value === "string",  
  number: (value: unknown): value is number => typeof value === "number"  
});  
  
is.string("hello"); // true  
is.not.string(42);  // true  
  
let value: string | number | undefined;  
  
if (is.number(value)) {  
  value.toFixed(2); // 'value' is number  
}  
  
if (is.not.number(value)) {  
  value.toFixed(2); // error: Property 'toFixed' does not exist on type 'undefined'.  
}  

@imhonglu/type-object

Bibliothèque wrapper type-safe de l’API native Object. Elle fournit des types proches du comportement natif.

import * as TypeObject from '@imhonglu/type-object';  
  
const data = { a: 1, b: 2, c: 3 };  
for (const key of TypeObject.keys(data)) {  
  // key: "a" | "b" | "c"  
  console.log(data[key]); // number  
}  
  
const string = 'hello';  
for (const index of TypeObject.keys(string)) {  
  // index: number & keyof string  
  console.log(string[index]); // string  
}  

@imhonglu/toolkit

Collection de types utilitaires et de fonctions utilitaires utilisés en interne dans le projet.

import type { Fn } from '@imhonglu/toolkit';  
  
// Fournit un alias de type pour le type de fonction '(...args: any[]) => any'.  
Fn.Callable // (...args: any[]) => any  
  
// Via les génériques, vous pouvez définir uniquement le type des arguments.  
Fn.Callable<{ args: [number, number] }> // (...args: [number, number]) => any  
  
// Via les génériques, vous pouvez définir uniquement le type de retour.  
Fn.Callable<{ return: string }> // (...args: any[]) => string  
  
// Via les génériques, vous pouvez définir à la fois le type des arguments et le type de retour.  
Fn.Callable<{ args: [number, number], return: string }> // (...args: [number, number]) => string  

Projets futurs et recherche d’emploi

La prochaine étape de ce projet en cours est de finaliser l’implémentation de la spécification JSON Schema,
puis j’aimerais écrire un framework backend.

Je suis actuellement en recherche d’emploi, donc tout intérêt porté à mon travail est le bienvenu.
Merci de m’avoir lu.

Je vous souhaite une excellente journée !

2 commentaires

 
jjpark78 2025-01-09

Dans ce domaine, il y a l’excellent zod, donc on l’utilise pour le produit, mais c’est intéressant.

 
honglu 2025-01-09

Les projets existants comme ajv, typia et zod sont aussi des projets que je suis avec beaucoup d’intérêt.

Dans le cas de safeParse de @imhonglu/format, c’est aussi une fonctionnalité influencée par l’API de zod.

Merci pour votre intérêt !