# Show GN: TypeScript 기반 JSON Schema 구현과 개발 도구 모음

> Clean Markdown view of GeekNews topic #18634. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=18634](https://news.hada.io/topic?id=18634)
- GeekNews Markdown: [https://news.hada.io/topic/18634.md](https://news.hada.io/topic/18634.md)
- Type: show
- Author: [honglu](https://news.hada.io/@honglu)
- Published: 2025-01-08T17:17:13+09:00
- Updated: 2025-01-08T17:17:13+09:00
- Original source: [github.com/imhonglu](https://github.com/imhonglu/new-wheels)
- Points: 6
- Comments: 2

## Summary

이 프로젝트는 타입 안전한 JSON Schema 구현을 목표로 시작되었으며, 개발 과정에서 필요한 다양한 도구들로 확장되었습니다. 주요 라이브러리로는 JSON Schema 2020-12 사양을 준수하는 `@imhonglu/json-schema`, JSON Schema의 format 키워드를 구현한 `@imhonglu/format`, 정규식 가독성을 높이기 위한 `@imhonglu/pattern-builder`, 타입 가드의 가독성을 향상시키는 `@imhonglu/type-guard`, 네이티브 Object API의 타입 안전한 래퍼인 `@imhonglu/type-object`, 그리고 유틸리티 타입과 함수 모음인 `@imhonglu/toolkit`이 포함됩니다. 프로젝트는 엄격한 타입 시스템 활용, 최소한의 외부 의존성 유지, 높은 테스트 커버리지 등의 원칙을 준수하며 개발되었습니다.

## Topic Body

"내 취향의 타입 안전한 라이브러리를 만들어보자"는 마음으로 시작한 프로젝트입니다.  
  
이 프로젝트는 타입 안전한 JSON Schema 구현체를 시작으로 개발 과정에서 필요한 다양한 도구들로 자연스럽게 확장되었습니다.  
  
현재 구직을 위해 1차적으로 마침표를 찍어보았습니다.  
  
### 프로젝트 원칙  
  
다음과 같은 핵심 원칙을 준수하며 개발되었습니다:  
  
- 엄격한 타입 시스템 활용  
- 최소한의 외부 의존성 유지  
- 재사용 가능한 타입 시스템 설계  
- API 문서화  
- 높은 테스트 커버리지 유지  
- 순수 타입스크립트 구현  
  
### 라이브러리  
  
#### @imhonglu/json-schema  
  
JSON Schema 2020-12 draft 사양을 준수하는 TypeScript 구현체입니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/json-schema/README_KR.md  
- `JSON-Schema-Test-Suite`를 통한 검증  
- 스키마 정의에 따라 사용 가능한 키워드의 타입이 자동으로 추론됩니다.  
  
![demo-1](https://raw.githubusercontent.com/imhonglu/new-wheels/refs/heads/main/libs/json-schema/assets/demo.gif)  
  
```ts  
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&lt;typeof Address&gt;;  
// {  
//   street: string;  
//   city?: string;  
//   zip?: string;  
// }  
```  
  
#### @imhonglu/format  
  
JSON Schema의 format 키워드를 구현하기 위해 시작된 프로젝트입니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/format/README_KR.md  
- RFC 사양 기반 구현  
- `JSON-Schema-Test-Suite` 기반 검증  
- 네이티브 `JSON` API와 유사한 인터페이스 제공  
  
```ts  
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 빌더입니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/pattern-builder/README_KR.md  
  
```ts  
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  
  
타입 가드의 가독성 향상을 위해 만들어진 타입 가드 라이브러리입니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/type-guard/README_KR.md  
- Proxy 기반의 구현으로 오버헤드 최소화  
- `not` 키워드 제공  
  
```ts  
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의 타입 안전한 래퍼 라이브러리입니다. 네이티브 동작에 가까운 타입을 제공합니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/type-object/README_KR.md  
  
```ts  
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  
  
프로젝트 내부에서 사용중인 유틸리티 타입과 유틸리티 함수들의 모음입니다.  
  
- 저장소: https://github.com/imhonglu/new-wheels/tree/main/libs/toolkit/README_KR.md  
  
```ts  
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 스펙 구현체를 마무리하고  
백엔드 프레임워크를 작성해보고 싶네요.  
  
현재 구직중이니 많은 관심 부탁드립니다.  
읽어주셔서 감사합니다.  
  
행복한 하루 되세요!

## Comments



### Comment 33175

- Author: jjpark78
- Created: 2025-01-09T13:31:32+09:00
- Points: 1

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

### Comment 33180

- Author: honglu
- Created: 2025-01-09T14:23:46+09:00
- Points: 1
- Parent comment: 33175
- Depth: 1

기성 프로젝트인 ajv, typia, zod 등 저도 관심 있게 보고 있는 프로젝트입니다.  
  
`@imhonglu/format`의 `safeParse` 같은 경우도 zod API 로 부터 영향 받은 기능이에요.  
  
관심 감사드립니다!
