6 Punkte von honglu 2025-01-08 | 2 Kommentare | Auf WhatsApp teilen

Dieses Projekt begann mit dem Gedanken: „Lass uns eine typsichere Bibliothek nach meinem Geschmack bauen.“

Ausgehend von einer typsicheren JSON-Schema-Implementierung hat es sich im Lauf der Entwicklung ganz natürlich zu einer Vielzahl von Werkzeugen erweitert, die im Entwicklungsprozess benötigt werden.

Vorerst habe ich im Zuge meiner Jobsuche einen ersten Abschluss gesetzt.

Projektprinzipien

Die Entwicklung folgte dabei den folgenden Kernprinzipien:

  • Nutzung eines strengen Typsystems
  • Möglichst geringe externe Abhängigkeiten
  • Entwurf eines wiederverwendbaren Typsystems
  • API-Dokumentation
  • Hohe Testabdeckung
  • Reine TypeScript-Implementierung

Bibliotheken

@imhonglu/json-schema

Eine TypeScript-Implementierung, die der Spezifikation des JSON Schema Draft 2020-12 entspricht.

[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

Dieses Projekt wurde gestartet, um das format-Keyword von JSON Schema zu implementieren.

  • Repository: https://github.com/imhonglu/new-wheels/…
  • Implementierung auf Basis der RFC-Spezifikationen
  • Verifizierung auf Basis der JSON-Schema-Test-Suite
  • Bietet eine Schnittstelle ähnlich der nativen JSON-API
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

Ein Regex-Builder, der während der Implementierung der ABNF-Grammatik aus den RFC-Spezifikationen entwickelt wurde, um die Lesbarkeit regulärer Ausdrücke zu verbessern.

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

Eine Type-Guard-Bibliothek, die entwickelt wurde, um die Lesbarkeit von Type Guards zu verbessern.

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

Eine typsichere Wrapper-Bibliothek für die native Object-API. Sie bietet Typen, die dem nativen Verhalten nahekommen.

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

Eine Sammlung von Utility-Typen und Utility-Funktionen, die intern im Projekt verwendet werden.

import type { Fn } from '@imhonglu/toolkit';  
  
// Bietet einen Typalias für den Funktionstyp '(...args: any[]) => any'.  
Fn.Callable // (...args: any[]) => any  
  
// Über Generics kann nur der Argumenttyp definiert werden.  
Fn.Callable<{ args: [number, number] }> // (...args: [number, number]) => any  
  
// Über Generics kann nur der Rückgabetyp definiert werden.  
Fn.Callable<{ return: string }> // (...args: any[]) => string  
  
// Über Generics können sowohl Argumenttyp als auch Rückgabetyp definiert werden.  
Fn.Callable<{ args: [number, number], return: string }> // (...args: [number, number]) => string  

Zukünftige Pläne und Jobsuche

Der nächste Schritt für das laufende Projekt ist, die Implementierung der JSON-Schema-Spezifikation abzuschließen
und mich an einem Backend-Framework zu versuchen.

Ich bin derzeit auf Jobsuche und freue mich über Ihr Interesse.
Vielen Dank fürs Lesen.

Ich wünsche Ihnen einen schönen Tag!

2 Kommentare

 
jjpark78 2025-01-09

In diesem Bereich gibt es mit zod bereits etwas Herausragendes, deshalb verwenden wir das im Produkt, aber es ist interessant.

 
honglu 2025-01-09

Ich verfolge auch etablierte Projekte wie ajv, typia und zod mit großem Interesse.

Auch safeParse von @imhonglu/format ist eine Funktion, die von der zod-API beeinflusst wurde.

Vielen Dank für Ihr Interesse!