6P by honglu 2달전 | ★ favorite | 댓글 2개

"내 취향의 타입 안전한 라이브러리를 만들어보자"는 마음으로 시작한 프로젝트입니다.

이 프로젝트는 타입 안전한 JSON Schema 구현체를 시작으로 개발 과정에서 필요한 다양한 도구들로 자연스럽게 확장되었습니다.

현재 구직을 위해 1차적으로 마침표를 찍어보았습니다.

프로젝트 원칙

다음과 같은 핵심 원칙을 준수하며 개발되었습니다:

  • 엄격한 타입 시스템 활용
  • 최소한의 외부 의존성 유지
  • 재사용 가능한 타입 시스템 설계
  • API 문서화
  • 높은 테스트 커버리지 유지
  • 순수 타입스크립트 구현

라이브러리

@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 스펙 구현체를 마무리하고
백엔드 프레임워크를 작성해보고 싶네요.

현재 구직중이니 많은 관심 부탁드립니다.
읽어주셔서 감사합니다.

행복한 하루 되세요!

이쪽으로는 zod라는 걸출한게 있어서 프로덕트에서는 그걸 쓰고 있습니다만, 흥미롭네요

기성 프로젝트인 ajv, typia, zod 등 저도 관심 있게 보고 있는 프로젝트입니다.

@imhonglu/formatsafeParse 같은 경우도 zod API 로 부터 영향 받은 기능이에요.

관심 감사드립니다!