6 ポイント 投稿者 honglu 2025-01-08 | 2件のコメント | WhatsAppで共有

「自分好みの型安全なライブラリを作ってみよう」という思いで始めたプロジェクトです。

このプロジェクトは、型安全なJSON Schema実装を出発点として、開発プロセスで必要になるさまざまなツールへと自然に拡張されていきました。

現在、求職のためにひとまず一区切りを付けてみました。

プロジェクト原則

次のような中核原則を守って開発しました:

  • 厳格な型システムの活用
  • 外部依存を最小限に維持
  • 再利用可能な型システムの設計
  • APIのドキュメント化
  • 高いテストカバレッジの維持
  • 純粋なTypeScript実装

ライブラリ

@imhonglu/json-schema

JSON Schema 2020-12 draft仕様に準拠したTypeScript実装です。

[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

JSON Schemaのformatキーワードを実装するために始まったプロジェクトです。

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

RFC仕様のABNF文法を実装する中で、正規表現の可読性向上のために作られたregexビルダーです。

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

型ガードの可読性向上のために作られた型ガードライブラリです。

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

ネイティブObject APIの型安全なラッパーライブラリです。ネイティブの動作に近い型を提供します。

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

プロジェクト内部で使っているユーティリティ型とユーティリティ関数のコレクションです。

import type { Fn } from '@imhonglu/toolkit';  
  
// 関数型 '(...args: any[]) => any' に対する型エイリアスを提供します。  
Fn.Callable // (...args: any[]) => any  
  
// ジェネリクスを通じて引数の型だけを定義できます。  
Fn.Callable<{ args: [number, number] }> // (...args: [number, number]) => any  
  
// ジェネリクスを通じて戻り値の型だけを定義できます。  
Fn.Callable<{ return: string }> // (...args: any[]) => string  
  
// ジェネリクスを通じて引数の型と戻り値の型を両方定義できます。  
Fn.Callable<{ args: [number, number], return: string }> // (...args: [number, number]) => string  

今後の計画と求職

進行中のプロジェクトの次の段階では、JSON Schema仕様の実装を仕上げ、
バックエンドフレームワークも書いてみたいと思っています。

現在求職中ですので、ぜひご関心をお寄せください。
読んでいただきありがとうございました。

良い一日をお過ごしください!

2件のコメント

 
jjpark78 2025-01-09

こちらの分野では zod という非常に優れたものがあるので、プロダクトではそれを使っていますが、興味深いですね。

 
honglu 2025-01-09

ajv、typia、zod などの既存プロジェクトは、私も関心を持って見ているプロジェクトです。

@imhonglu/formatsafeParse も、zod API から影響を受けた機能です。

ご関心をお寄せいただき、ありがとうございます!