🧬 JSON → 타입 정의 변환
JSON을 붙여넣으면 TypeScript / PHP / Python / Go / Rust 타입 정의를 자동 생성합니다. 중첩된 객체와 배열을 지원.
💡 사용 팁
• 중첩된 객체는 자동으로 별도 타입으로 추출됩니다.
• 배열 요소에서 타입을 추론합니다. 빈 배열은 any[] / []interface{} 등이 됩니다.
• null은 string | null 같은 optional / nullable로 처리됩니다.
• 루트 타입 이름은 위 입력 필드에서 변경할 수 있습니다.
🔗 관련 도구
📖 자주 걸리는 지점
JSON 을 붙여 넣으면 TypeScript / PHP / Python / Go / Rust / Kotlin / Swift 의 타입 정의를 생성합니다. 중첩된 오브젝트는 별도의 타입으로 추출되고 배열의 요소에서도 타입을 추론합니다. 처리는 브라우저 안에서 끝납니다. 추론할 수 있는 것은 건넨 샘플에 나타난 형태뿐입니다 — API 의 응답 한 건은 그때 돌아온 형태이지 사양이 아닙니다. 생성물은 완성품이 아니라 손으로 고치기 위한 출발점이라고 생각하세요.
| 사례 | 무슨 일이 일어나는가 | 어떻게 하면 되는가 |
|---|---|---|
| 샘플 한 건에서 만든 타입이 프로덕션에서 맞지 않는다 | 추론은 본 것이 전부라는 전제로 동작합니다. 따라서 그 샘플에 나타나지 않은 필드는 타입에 존재하지 않고 우연히 값이 들어 있던 필드는 필수로 다뤄집니다. 실제 API 는 검색 결과가 0 건일 때, 에러일 때, 권한이 부족할 때, 오래된 레코드일 때 각각 다른 형태를 반환합니다. 특히 위험한 것이 enum 적인 필드로 샘플에 "active" 밖에 없으면 타입은 "active" 라는 리터럴 타입이 되고 "archived" 가 오는 순간 타입이 거짓말이 됩니다. |
복수의 응답을 통과시키세요 — 정상 · 빈 결과 · 에러 · 경곗값의 네 패턴을 최소한으로 하고 생성된 타입을 맞춰 보면 어느 필드가 정말로 필수인지가 보이기 시작합니다. OpenAPI 사양이 있다면 그쪽에서 생성하세요 — openapi-typescript 나 oapi-codegen 은 돌아올 수 있는 형태를 사양으로 갖고 있으므로 샘플에서의 추론과는 신뢰성이 다릅니다. 그리고 생성한 타입은 반드시 한 번 읽으세요 — 전 필드가 필수, enum 이 리터럴 하나인 타입이 나왔다면 그것은 샘플이 한 건이었다는 신호입니다. |
| 빈 배열이나 null 에서는 타입이 정해지지 않는다 | "tags": [] 라는 값에서는 요소의 타입을 알 방법이 없습니다 — 결과는 any[] · []interface{} · List<Any> 같은 무엇이든 들어가는 타입이 되어 타입 검사의 혜택이 완전히 사라집니다. null 도 마찬가지로 정보가 부족합니다 — "deleted_at": null 이 늘 null 인지 이번만 null 인지는 이 한 건에서는 판별할 수 없습니다. 나아가 근본적인 문제로 JSON 에서는 키가 존재하지 않는 것과 키의 값이 null 인 것을 구별할 수 있지만 많은 언어의 타입 시스템에서는 이 구별이 모호해집니다 — TypeScript 의 ?: 와 | null 은 별개입니다. |
빈 배열을 포함하는 응답은 요소가 들어 있는 다른 응답도 통과시키세요 — 한 건이라도 요소가 있으면 타입이 정해집니다. 그것을 손에 넣을 수 없다면 그 배열의 타입만 손으로 쓰세요 — 생성물을 그대로 쓰는 것이 아니라 9 할을 자동화하고 나머지를 채우는 것 이라고 생각하면 이 작업은 부담이 되지 않습니다. null 의 취급은 API 의 문서를 보는 수밖에 없습니다 — 키가 없음 과 null 을 구별하는 API 라면 TypeScript 에서는 deleted_at?: string | null 처럼 양쪽을 쓰는 것이 정확합니다. 망설여지면 느슨한 쪽으로 기울이세요 — 타입이 느슨하고 실행 시에 검사하는 편이 타입이 엄격하고 실행 시에 떨어지는 것보다 안전합니다. |
| 숫자의 타입이 언어에 따라 의미를 바꾼다 | JSON 의 숫자는 한 종류밖에 없습니다 — 정수와 소수의 구별도 정밀도의 지정도 없습니다. 따라서 생성 쪽은 언어마다 무언가를 고를 수밖에 없어 Go 라면 float64, Rust 라면 i64 나 f64, TypeScript 라면 number 가 됩니다. 여기서 위험한 것이 ID 입니다 — 큰 정수를 float64 나 number 로 받으면 2 의 53 제곱을 넘은 시점에 정밀도가 떨어져 값이 조용히 바뀝니다. 9007199254740993 이 9007199254740992 가 되어도 에러는 나지 않습니다. 날짜 같은 문자열도 당연히 string 그대로입니다. |
ID · 금액 · 일시는 생성 후에 반드시 손으로 타입을 고치세요. ID 는 문자열로 다루는 것이 가장 안전합니다 — 계산하지 않는 값을 숫자로 가질 이유는 없습니다(실제로 Twitter 나 Discord 의 API 는 큰 ID 를 문자열로 반환합니다). 금액은 부동소수점으로 하지 마세요 — 0.1 + 0.2 가 0.3 이 되지 않는 것과 같은 이유로 최소 단위의 정수나 언어의 Decimal 타입을 쓰세요. 일시는 string 이 아니라 각 언어의 일시 타입으로 고치면 타임존의 취급을 타입이 강제해 줍니다. 생성한 타입을 한 줄씩 읽고 이 값으로 계산하는가를 자문하세요 — 계산하지 않는다면 문자열로 상관없습니다. |
생성한 타입을 믿을 수 있는 경계라고 생각하지 마세요. 특히 TypeScript 의 타입은 컴파일 시에만 존재하고 실행 시에는 아무것도 검증하지 않습니다 — await res.json() as User 라고 쓰면 실제로 돌아온 것이 무엇이든 컴파일러는 User 라고 믿습니다. 이는 타입 시스템의 결함이 아니라 경계에서의 검증은 다른 레이어의 일이라는 설계입니다. API 의 응답이나 폼의 입력처럼 밖에서 오는 데이터에는 zod 나 valibot 같은 런타임 검증을 반드시 넣으세요 — 스키마에서 타입을 도출할 수 있으므로 이중 관리도 되지 않습니다. Go 의 json.Unmarshal 이나 Rust 의 serde 는 실제로 검증하므로 그나마 안전하지만 기본적으로는 알 수 없는 필드를 조용히 버립니다 — Go 라면 DisallowUnknownFields, Rust 라면 #[serde(deny_unknown_fields)] 로 API 의 변경을 알아챌 수 있게 됩니다.
📖 사용법
-
1
JSON 입력 또는 붙여넣기왼쪽 입력란에 JSON을 붙여넣으세요. 샘플 버튼으로 예시 데이터를 빠르게 확인할 수 있습니다.
-
2
대상 언어 선택TypeScript, PHP, Python, Go, Rust, Kotlin, Swift 중 언어를 선택하고 루트 타입 이름을 변경하세요.
-
3
타입 정의 복사하여 사용오른쪽에 자동 생성된 타입 정의가 표시됩니다. 복사 버튼으로 클립보드에 복사하세요.
❓ 자주 묻는 질문
중첩된 객체는 어떻게 처리되나요?
null 필드는 어떻게 타입이 지정되나요?
최상위 JSON 배열도 지원하나요?
🐛 이 도구에서 문제가 발생했나요?
무료 · 가입 불필요. 재현 절차만이라도 도움이 됩니다. 보고는 운영자에게 직접 전달되어 개선에 사용됩니다.
보고 감사합니다!
운영자에게 전달되었습니다. 개선에 사용됩니다.