입력 (.proto 스키마)

출력 (TypeScript)

이 도구가 하는 일

Protocol Buffers 스키마가 있고, 그 메시지를 제공하는 gRPC 또는 HTTP-트랜스코드 백엔드와 통신해야 하는 TypeScript 프론트엔드를 가지고 있는 상황을 위한 도구입니다. 공식 codegen 툴체인(protocts-proto 또는 protobuf-ts)은 도구 설치, 플러그인 설정, 빌드 단계 연결이 필요합니다. 이 변환기는 같은 작업을 브라우저 안에서 합니다 — 붙여넣고, 출력을 복사해서, 프로젝트에 넣으면 끝입니다.

타입 매핑은 실제 코드베이스에서 직접 작성하는 타입의 모습을 따릅니다: string/bytesstring/Uint8Array, boolboolean, 작은 숫자 타입(int32, uint32, float, double) → number, 64비트 정수 타입(int64, uint64, fixed64, sfixed64, sint64) → string으로, proto3 JSON 매핑 스펙에 맞춥니다. repeated TT[]가 되고, map<K, V>Record<K, V>가 되며, 중첩된 메시지는 중첩된 interface 선언이 됩니다.

필드 이름은 snake_case(Protobuf 관습)에서 camelCase(JavaScript/TypeScript 관습)로 변환됩니다 — proto3 JSON 인코더의 기본 동작과 일치합니다. enum은 문자열 리터럴 union 타입(type OrderStatus = 'ORDER_STATUS_UNSPECIFIED' | 'ORDER_STATUS_PENDING' | ...)이 되며, 이는 대부분의 TypeScript 코드베이스가 실제로 원하는 형태입니다 — enum의 런타임 오버헤드가 필요 없습니다. 변환기는 전적으로 브라우저에서 실행되며, 스키마는 페이지 밖으로 나가지 않습니다.

사용 방법

세 단계. 출력은 몇 초 안에 <code>.ts</code> 파일에 붙여넣을 준비가 됩니다.

1

.proto 스키마를 붙여넣기

왼쪽 에디터에 스키마를 넣습니다. 맨 위의 syntax = "proto3";는 있어도 좋지만 선택 사항입니다. 파서는 중첩된 message 블록, enum 선언, oneof, map<K, V>, 필드 옵션을 처리합니다. import는 인식되지만 건너뜁니다 — 필요하다면 import된 타입을 인라인으로 붙여넣으세요.

필드 이름 변환은 자동입니다: .protoorder_id는 TypeScript에서 orderId가 됩니다. 메시지와 enum 이름은 그대로 유지됩니다(이미 PascalCase).

2

출력 읽기

오른쪽: 각 메시지에 대한 export interface와 각 enum에 대한 문자열 리터럴 union의 export type을 가진 TypeScript. 중첩 타입은 부모 앞에 와서 파일이 선언 순서로 정렬됩니다. 파일을 프로젝트에 추가하고 gRPC 클라이언트나 fetch 핸들러에서 인터페이스를 import하세요.

3

타입 사용하기

fetch / gRPC-Web / Connect-RPC 클라이언트에 인터페이스를 연결하세요. 모양이 proto3 JSON 인코딩과 일치하므로 JSON 응답이 수동 변환 없이 바로 타입이 지정된 형태로 파싱됩니다. 서버가 비표준 JSON 인코딩을 사용하면 int64 처리를 조정하세요.

실제로 시간을 절약하는 경우

새로운 gRPC 프론트엔드의 타입 스케치

기존 gRPC 서비스 위에 새로운 TS 앱을 만들고 있습니다. 아직 풀 codegen은 필요 없고 — fetch 호출에 타입을 지정할 인터페이스 모양만 있으면 됩니다. .proto를 붙여넣고 출력을 types.ts에 넣으면 타입 지정이 끝납니다.

Protobuf API 변경 리뷰

백엔드 동료가 메시지에 필드를 추가했습니다. 빌드를 돌리지 않고 프론트엔드 타입에 어떻게 영향을 미치는지 보고 싶습니다. 새 .proto를 붙여넣고 TypeScript 출력을 현재 타입과 비교한 뒤, 핵심을 짚는 리뷰 코멘트를 남기세요.

생성된 타입 교차 확인

빌드가 protobuf-ts 또는 ts-proto를 사용하는데, 이들은 자체 관습으로 타입을 생성합니다. 평범한 TS 인터페이스가 어떻게 보이는지에 대한 깔끔한 참고용으로 여기에 스키마를 붙여넣으세요. 문서나 마이그레이션 계획에 유용합니다.

일회성 스크립트와 단발 통합

gRPC 게이트웨이에 JSON을 POST하는 빠른 Node 스크립트를 작성 중입니다. 30줄짜리 스크립트를 위해 Protobuf 풀 툴체인을 세팅하는 건 과합니다. 여기서 인터페이스만 가져가면 번거로움 없이 타입 안정성을 얻습니다.

자주 묻는 질문

제 스키마가 어딘가로 전송되나요?

아니요. 파서와 TS 이미터는 완전히 브라우저 안에서 JavaScript로 실행됩니다. DevTools를 열고 붙여넣는 동안 Network 탭을 보세요 — 요청은 0개입니다. 스키마에 내부 타입 이름, 패키지 경로 또는 제3자 서비스에 보내고 싶지 않은 것이 포함된 경우에 유용합니다.

왜 int64 필드가 string으로 타입 지정되나요?

JavaScript의 Number는 IEEE-754 double이며 2^53 이상에서는 정밀도를 잃습니다. 공식 proto3 JSON 매핑int64, uint64, fixed64, sfixed64, sint64를 JSON 문자열로 인코딩하도록 요구합니다. 그래서 TS 인터페이스는 그것들에 string을 사용합니다 — 서버가 실제로 보내는 것과 일치합니다. bigint가 필요하면 출력에서 찾아 바꾸기를 하세요.

왜 enum이 TS enum이 아니라 문자열 union인가요?

요즘 대부분의 TypeScript 프로젝트는 TS enum보다 문자열 리터럴 union을 선호합니다 — 런타임 비용이 없고, tree-shaking이 더 잘 되며, proto3 JSON 인코딩(enum을 문자열 이름으로 직렬화)과 일치합니다. const enum이나 숫자 enum을 원한다면 union에서의 변환은 기계적입니다.

map<K, V>는 어떻게 처리되나요?

Record<K, V>로 렌더링됩니다. 문자열이 아닌 키를 가진 Protobuf 맵(예: map<int32, string>)은 Record<number, string>이 됩니다. JSON은 문자열 키만 있으므로 런타임에 키는 proto가 int라고 해도 문자열이 됩니다 — 이는 proto3 JSON 스펙의 특이한 점이지 변환기의 문제가 아닙니다.

필드가 옵셔널로 표시되나요?

아니요. proto3 필드는 항상 JSON 출력에 존재합니다(기본값과 함께 — 빈 문자열, 0, false, [], {}). 따라서 TypeScript 인터페이스는 모든 필드를 필수로 표시합니다. 정말로 옵셔널 필드를 원한다면(런타임이 생략할 수 있어서) 각 필드 이름 뒤에 ?를 직접 추가하세요.

oneof를 처리하나요?

각 oneof 필드는 일반 인터페이스 필드로 방출됩니다. 출력은 oneof가 의미하는 "정확히 하나" 제약을 강제하지 않습니다 — 그러려면 판별 가능한 union이 필요한데, 이는 런타임 시맨틱에 따라 다릅니다. 더 엄격한 타입이 필요하면 출력을 직접 편집하세요.

관련 도구

Protobuf, JSON, TypeScript로 작업한다면 다음 도구들이 잘 어울립니다: