Skip to content
블로그로 돌아가기
튜토리얼

JSON을 TypeScript로 변환: 인터페이스와 타입 생성 가이드 (2026)

JSON을 TypeScript로 변환하세요. 타입 추론 규칙, interface와 type 비교, 선택적·유니온 필드, 흔한 함정까지 온라인으로 정리했습니다. 무료로 사용해 보세요.

11 분 소요

JSON을 TypeScript로 변환 (JSON to TypeScript)

JSON에서 TypeScript로 가장 빠르게 넘어가는 방법은 페이로드를 JSON to TypeScript 변환기에 붙여넣고 생성된 인터페이스를 복사하는 것입니다. 설치도, 업로드도 없이 브라우저 안에서 끝납니다. “지금 당장 타입이 필요하다”는 상황은 이걸로 해결됩니다.

하지만 타입을 생성하는 것과 좋은 타입을 생성하는 것은 별개의 문제입니다. 변환기는 추측할 수밖에 없습니다. 이 필드는 선택적인 걸까요, 아니면 단지 한 샘플에서 빠진 걸까요? 저 배열은 항상 문자열일까요, 아니면 가끔 숫자도 섞일까요? 날짜 문자열은 Date로 바꿔야 할까요? 이 가이드에서는 추론이 실제로 어떻게 동작하는지, interfacetype 중 무엇을 언제 써야 하는지, 실제 API 응답을 믿을 만한 타입으로 만들 때 부딪히는 함정은 무엇인지 다룹니다.

JSON을 TypeScript로 변환하는 방법

JSON을 TypeScript로 변환하는 과정은 세 단계입니다.

  1. JSON을 붙여넣으세요. 객체, 배열, 또는 가공하지 않은 API 응답을 입력 상자에 넣으면 됩니다. 변환은 전적으로 클라이언트 측에서 즉시 실행됩니다.
  2. 출력을 조정하세요. interfacetype 중 하나를 고르고, UserApiResponse 같은 루트 이름을 지정하고, export 키워드를 켜거나 끄고, 선택적 필드에 ?:| null 중 어느 것을 쓸지 선택하세요.
  3. 복사하거나 다운로드하세요. 생성된 TypeScript를 클릭 한 번으로 가져와 코드베이스에 그대로 붙여넣으면 됩니다.

바로 쓰고 싶은 사람은 여기까지면 됩니다. JSON to TypeScript 변환기는 입력을 읽어 타입 트리를 추론하고 오른쪽에 정의를 출력합니다. 그 어떤 것도 페이지를 벗어나지 않습니다. 이 가이드의 나머지는 변환기가 추측할 수 없는 부분을 직접 손볼 수 있도록 그 결과물을 이해하는 데 초점을 맞춥니다.

JSON 타입이 TypeScript로 매핑되는 방식

모든 JSON 값에는 대응하는 TypeScript 타입이 있습니다. 매핑은 대부분 일대일입니다.

JSON 값TypeScript 타입
"text"string
42, 3.14number
true / falseboolean
nullnull
[1, 2, 3]number[]
{ ... }interface 또는 type

작업이 일어나는 곳은 객체입니다. 전형적인 REST 사용자 페이로드를 예로 들어 보겠습니다.

{
  "id": 101,
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "active": true,
  "roles": ["admin", "user"]
}

변환기는 이 JSON으로부터 다음과 같은 TypeScript 인터페이스를 생성합니다.

export interface User {
  id: number;
  name: string;
  email: string;
  active: boolean;
  roles: string[];
}

각 스칼라 값은 해당 원시 타입으로 매핑되고, roles 배열은 string[]이 됩니다. 이것을 API 클라이언트에 넣으면 자동 완성과 컴파일 타임 검사를 공짜로 얻을 수 있습니다.

변환기가 타입을 추론하는 방식

흥미로운 부분은 추론 알고리즘입니다. 네 가지 규칙이 여러분이 던질 거의 모든 입력을 처리합니다.

구조적 추론: 객체마다 이름 있는 인터페이스 하나

서로 다른 객체 형태는 각각 자기만의 이름 있는 인터페이스가 됩니다. 중첩된 객체는 인라인 타입으로 합쳐지지 않고, 별도의 참조되는 정의로 끌어올려집니다.

{
  "order": {
    "id": "A-1",
    "total": 42.5,
    "customer": { "name": "Sam", "vip": false }
  }
}
export interface Root {
  order: Order;
}

export interface Order {
  id: string;
  total: number;
  customer: Customer;
}

export interface Customer {
  name: string;
  vip: boolean;
}

형태가 동일한 객체는 중복이 제거되므로, 구조가 같은 두 필드는 복사본을 만드는 대신 하나의 인터페이스를 공유합니다.

배열 병합: 선택적 필드 추론하기

객체 배열을 넘기면 변환기는 키 단위로 객체들을 병합합니다. 어떤 키가 일부 요소에만 있고 다른 요소에는 없다면, 그 키는 선택적으로 표시됩니다.

{
  "users": [
    { "id": 1, "nick": "x" },
    { "id": 2 }
  ]
}
export interface Root {
  users: User[];
}

export interface User {
  id: number;
  nick?: string;
}

id는 모든 요소에 있으므로 필수로 남습니다. nick은 두 번째 사용자에서 빠져 있으므로 nick?: string이 됩니다. 단일 샘플로는 충분하지 않은 경우가 많은 이유가 바로 이것입니다. 아래 함정 섹션을 참고하세요.

혼합 배열을 위한 유니온 타입

배열이 반드시 동질적일 필요는 없습니다. 요소들의 타입이 서로 다르면 변환기는 그것들을 유니온으로 모읍니다.

{
  "tags": ["a", "b"],
  "meta": [1, "two"]
}
export interface Root {
  tags: string[];
  meta: (string | number)[];
}

tags는 한결같이 문자열이므로 string[]입니다. meta는 숫자와 문자열이 섞여 있어 (string | number)[]가 됩니다. 빈 배열은 아예 추론할 수 없어 unknown[]으로 처리됩니다. 요소가 0개면 알아낼 정보가 없으니, 솔직히 이게 맞는 결과입니다.

선택적 vs null: ?:| null

이 둘은 비슷해 보이지만 의미가 다릅니다. ?:로 표시된 필드는 객체에서 완전히 빠질 수 있습니다. | null 타입의 필드는 항상 존재하지만 값으로 null을 가질 수 있습니다.

{ "score": null }
export interface Root {
  score: number | null;
}

여기서 score는 명시적인 null과 함께 존재하므로 number | null로 타이핑됩니다. 값은 있고, 다만 null일 뿐입니다. 키 자체가 통째로 빠질 수 있는 배열 예시의 nick?: string과 대조됩니다. API가 키를 생략할 수 있을 때는 ?:를, 키를 null 값과 함께 보낼 때는 | null을 쓰세요. 대부분의 변환기는 이것이 어떻게 렌더링될지 토글로 제어할 수 있게 해 줍니다.

interface vs type: 무엇을 써야 할까?

둘 다 객체 형태를 표현할 수 있습니다. 어떻게 결정하면 되는지 정리했습니다.

필요한 것사용할 것
JSON에서 나온 평범한 객체 형태interface
유니온(A | B) 또는 인터섹션(A & C)type
선언 병합 / 파일 간 확장interface
매핑 타입 또는 조건부 타입type
약간 더 깔끔한 편집기 오류 메시지interface

JSON 객체에서 나온 데이터라면 interface가 관례적인 선택이며 컴파일러 오류도 미세하게 더 보기 좋습니다. 하지만 유니온이 필요해지는 순간, 예를 들어 성공이거나 오류인 Result 같은 것이라면 type으로 전환해야 합니다. 인터페이스는 유니온을 표현할 수 없기 때문입니다.

type ApiResult =
  | { status: "ok"; data: User }
  | { status: "error"; message: string };

권장하는 기본값은 이렇습니다. 평범한 JSON 객체에는 interface를 생성하고, 형태에 유니온이나 인터섹션이 필요해지면 type으로 바꾸는 것입니다. 전체 비교가 궁금하다면 TypeScript 핸드북이 엣지 케이스까지 다룹니다. 인터페이스 대신 json to typescript type 별칭이 필요할 때, 대부분의 변환기는 출력 전체를 뒤집을 수 있는 토글 하나를 제공합니다.

quicktype vs json-to-ts vs 온라인 도구 vs 수작업

TypeScript 타입을 생성하는 단 하나의 최선책은 없습니다. JSON이 어디에 있고 얼마나 자주 바뀌는지에 따라 달라집니다.

방식적합한 경우절충점
quicktype여러 언어로 출력, 런타임 유효성 검사 코드 생성더 무겁고, 필요 이상으로 많은 출력
json-to-ts (라이브러리)스크립트나 파이프라인에 엮인 빌드 타임 코드 생성설정과 Node 툴체인이 필요
브라우저 기반 온라인 도구일회성 변환, 민감한 페이로드, 설치 불필요매번 수동으로 붙여넣기
타입을 손으로 작성아주 작은 객체, 타입 시스템 학습규모가 커지면 번거롭고 실수가 잦음

여러 언어로 타입이 필요하거나 타입과 함께 검증기를 내보내고 싶다면 quicktype을 고르세요. 변환이 빌드 단계에 속한다면 json-to-ts 라이브러리를 고르세요. 빠른 변환, 특히 토큰·고객 ID처럼 원격 서비스에 붙여넣고 싶지 않은 것이 담긴 페이로드라면, 브라우저 도구가 개인정보 보호와 속도에서 앞섭니다. 저희 JSON to TypeScript 변환기는 완전히 클라이언트 측에서 동작합니다. JSON은 페이지를 절대 벗어나지 않고, 설치하거나 업데이트할 것도 없습니다.

타입은 유효성 검사가 아닙니다: 런타임 검사로 잇기

여기서 발이 걸리는 팀이 많으니 분명히 해 둡니다. TypeScript 타입은 컴파일 타임에 지워지며 런타임에는 아무것도 하지 않습니다. 생성된 interface User는 실제 API 응답이 그것과 일치하는지 검사하지 않습니다. 서버가 id를 숫자가 아니라 문자열로 보내도, TypeScript는 여러분의 타입 주석을 순순히 믿는데 실제 데이터는 거짓말을 하고 있는 셈입니다.

타입을 generate typescript types 하는 동시에 실제 데이터에서 그것을 강제하려면, 타입을 런타임 유효성 검사기와 짝지으세요.

  • zod — 스키마를 한 번 정의하고, 거기서 정적 타입을 추론하고, 런타임에 응답을 파싱합니다.
  • io-ts — 코덱 기반 유효성 검사로, 함수형 코드베이스에서 인기가 있습니다.
  • JSON Schema + Ajv — 런타임에 검증되는 언어 중립적 스키마로, 계약이 여러 서비스에 걸쳐 공유될 때 유용합니다.

흔한 패턴은 편집기 지원을 위해 인터페이스를 생성한 다음, 실제 경계 검사로 쓸 zod 스키마를 그에 맞춰 작성하는 것입니다.

import { z } from "zod";

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
  active: z.boolean(),
  roles: z.array(z.string()),
});

type User = z.infer<typeof UserSchema>;

// 실제 응답이 스키마와 일치하지 않으면 예외를 던집니다.
const user = UserSchema.parse(await res.json());

스키마 방식으로 갈 생각이라면, 저희 JSON Schema 유효성 검사 가이드가 스키마 작성부터 강제까지 처음부터 끝까지 안내합니다.

JSON에 타입을 매길 때 흔한 함정

생성된 타입은 출발점이지 완성품이 아닙니다. 다음을 주의하세요.

snake_case vs camelCase. 변환기는 키를 있는 그대로 유지합니다. public_repos가 들어 있는 GitHub 스타일 페이로드는 publicRepos가 아니라 public_repos: number를 만들어 냅니다. 코드베이스가 camelCase를 선호한다면, snake_case 타입을 그대로 받아들이거나 들어오는 길목에서 필드 이름을 바꿔 주는 매핑 계층을 추가해야 합니다.

날짜 문자열은 string으로 남습니다. "2026-06-01T00:00:00Z" 같은 필드는 Date가 아니라 string으로 타이핑됩니다. 이는 의도된 동작입니다. JSON에는 날짜 타입이 없고, 잘못 추측하는 것은 정직한 것보다 나쁘기 때문입니다. 문자열을 Date로 변환하는 일은 여러분이 직접 통제하는 파싱 계층에 속합니다.

anyunknown 누출. 빈 배열은 unknown[]이 되고, 복잡하게 뒤섞인 구조는 느슨한 타입으로 떨어질 수 있습니다. 이는 버그가 아니라, 데이터가 부족해 추론할 수 없다고 변환기가 인정하는 것입니다. 실제 형태를 알게 되면 손으로 직접 조여 주세요.

깊은 중첩의 폭발. 깊게 중첩된 페이로드는 작은 인터페이스의 긴 사슬을 생성합니다. 대개는 괜찮으며 하나의 거대한 인라인 타입보다 읽기 좋지만, 자기 이름을 가질 만큼 가치가 없는 형태는 평탄화할 만합니다.

단일 샘플의 함정. 이것이 가장 큰 걸림돌입니다. 선택적 필드는 여러 배열 요소에서만 추론할 수 있습니다. 객체 하나로는 어떤 키가 가끔 빠지는지 변환기에 알려 줄 수 없습니다. 대표성을 갖춘 응답 배열을 먼저 모으세요. 변환하기 전에 여러 샘플을 나란히 붙여넣고 살펴보는 데는 JSON 포맷터가 편리하며, JSONC처럼 비표준 입력을 다룬다면 저희 JSON5 / JSONC 가이드를 읽어 보세요. 변환기에는 엄격하게 유효한 JSON이 필요합니다.

자주 묻는 질문

JSON을 TypeScript 인터페이스로 어떻게 변환하나요?

JSON을 JSON to TypeScript 변환기에 붙여넣으세요. 브라우저 안에서 입력을 읽어 TypeScript 인터페이스를 즉시 생성합니다. 복사 버튼을 누르면 결과를 가져올 수 있습니다. 업로드도, 계정도, 설치할 플러그인도 없습니다.

JSON 데이터에는 interfacetype 중 무엇을 써야 하나요?

JSON에서 나온 평범한 객체 형태에는 interface를 쓰세요. 관례적이고 편집기 오류도 약간 더 명확합니다. 유니온이나 인터섹션이 필요할 때는 type으로 전환하세요. 인터페이스로는 그것들을 표현할 수 없기 때문입니다.

중첩된 객체와 배열은 어떻게 처리되나요?

중첩된 객체는 별도의 이름 있는 인터페이스가 됩니다(address 필드는 Address 인터페이스가 됩니다). 객체 배열은 키 단위로 병합되어 하나의 요소 인터페이스가 되고, 원시 값 배열은 string[] 같은 타입 배열이 됩니다.

선택적 필드와 null 필드는 어떻게 타이핑되나요?

일부 배열 요소에서 빠진 키는 선택적으로 표시됩니다(nick?: string). 항상 존재하지만 null을 담는 키는 | null로 타이핑됩니다(score: number | null). 둘은 서로 다른 상황을 나타냅니다. 부재(absent)와 존재하지만-null(present-but-null)입니다.

TypeScript 타입은 런타임에 JSON을 검증하나요?

아닙니다. TypeScript 타입은 컴파일 타임에 지워지며 런타임에는 데이터를 검사하지 않습니다. 실제 API 응답을 검증하려면, 생성된 타입을 zod, io-ts, 또는 Ajv를 곁들인 JSON Schema 같은 런타임 유효성 검사기와 짝지으세요.

quicktype vs json-to-ts vs 온라인 변환기 — 어느 것이 가장 좋나요?

quicktype은 여러 언어로의 출력과 런타임 검증기에 적합하고, json-to-ts 라이브러리는 빌드 타임 코드 생성에 적합하며, 온라인 변환기는 설치가 필요 없는 빠르고 비공개적인 일회성 변환에 적합합니다. 민감한 페이로드라면 클라이언트 측 브라우저 도구가 데이터를 어떤 서버에도 보내지 않습니다.

날짜 문자열은 왜 Date가 아니라 string으로 타이핑되나요?

JSON에는 날짜 타입이 없으므로, 전송 중인 날짜는 그저 문자열입니다. 그것을 string으로 타이핑하는 것이 정직하고 안정적입니다. Date로 변환하는 것은 형식과 오류 처리를 직접 통제하는 파싱 계층에서 내릴 결정입니다.

온라인 변환기를 쓸 때 제 JSON 데이터는 비공개로 유지되나요?

클라이언트 측 도구라면 그렇습니다. 변환은 JavaScript를 사용해 전적으로 여러분의 브라우저 안에서 실행되므로, 토큰·ID·고객 데이터를 포함한 JSON이 페이지를 절대 벗어나지 않고 서버로 전송되지도 않습니다.