TypeScript
테이블 스키마별로 TypeScript 타입 정의를 자동으로 생성하는 방법을 설명합니다.
TypeScript 타입 정의
Onttle은 Table 스키마를 기반으로 TypeScript 타입 정의를 자동으로 생성합니다. Column을 추가하거나 변경하면 정의가 즉시 다시 생성되므로, 프론트엔드 코드에서 타입을 직접 작성하거나 관리하지 않고도 Contents를 타입 안전하게 다룰 수 있습니다.
위치
Project 좌측 메뉴에서 TypeScript를 열면 해당 Project의 모든 Table에 대한 타입 정의를 확인할 수 있습니다.
/workspaces/{workspaceId}/projects/{projectId}/typescript
Contents 툴바의 TypeScript definitions 버튼을 클릭하면 해당 Table의 정의로 바로 이동합니다.
[IMAGE AREA] TypeScript 페이지 — Tables / Predefined 탭과 생성된 정의 블록
이 페이지는 두 개의 탭으로 구성됩니다.
| 탭 | 설명 |
|---|---|
| Tables | 각 Table의 Column을 기준으로 생성되는 Request / Response 인터페이스 |
| Predefined | ProjectFile, Category, Variable 등 모든 Table에서 공통으로 참조하는 타입 |
각 정의 블록에는 코드를 복사하는 복사 버튼이 있으며, Table 블록에는 해당 Table의 콘텐츠로 이동, API 엔드포인트로 이동 바로가기가 함께 제공됩니다.
Tables 탭
각 Table마다 Contents를 생성하거나 수정할 때 사용하는 요청 본문용 Request 인터페이스와, API가 반환하는 데이터 형태를 나타내는 Response 인터페이스가 생성됩니다.
타입 이름
Table 이름은 PascalCase로 변환되어 타입 이름의 접두어로 사용됩니다. 이름이 숫자로 시작하면 앞에 Table을 붙입니다.
| Table 이름 | 생성되는 타입 이름 접두어 |
|---|---|
blog-post |
BlogPost |
2024_promo |
Table2024Promo |
Request 인터페이스
export interface BlogPostRequest {
slug?: string
seo_title?: string
seo_description?: string
seo_image?: string
is_publish?: boolean
title: string
body?: string
}
| 필드 | 포함 조건 |
|---|---|
slug |
Table에 Slug 옵션이 활성화된 경우 |
seo_title / seo_description / seo_image |
Table에 SEO 필드가 활성화된 경우 |
is_publish |
항상 포함 |
| Column 필드 | 편집 가능한 모든 Column, Column의 name을 키로 사용 |
Column에 필수(Required) 옵션이 설정되지 않은 경우 필드는 선택(?) 값으로 생성됩니다. SEPARATOR, LABEL, UNKNOWN 타입의 Column은 레이아웃 전용이므로 생성되는 인터페이스에서 제외됩니다.
Response 인터페이스
export interface BlogPostResponse {
id: string
slug: string
created_at: string
updated_at: string
published_at: string | null
data: {
title: string
body: string
}
}
| 필드 | 포함 조건 |
|---|---|
id, created_at, updated_at, published_at |
항상 포함 |
slug |
Table에 Slug 옵션이 활성화된 경우 |
seo_title / seo_description / seo_image |
Table에 SEO 필드가 활성화된 경우 (seo_image: ProjectFile) |
data |
SEPARATOR, LABEL, UNKNOWN을 제외한 모든 Column |
Column의 name이 유효한 TypeScript 식별자가 아닌 경우(공백을 포함하거나 숫자로 시작하는 등) 해당 키는 문자열 리터럴로 감싸 표기합니다.
Column 타입 매핑
각 Column 타입은 다음과 같이 TypeScript 타입으로 매핑됩니다. Request 열은 입력에 사용하는 타입을, Response 열은 API가 반환하는 타입을 나타냅니다.
| Column 타입 | Request 타입 | Response 타입 |
|---|---|---|
NUMBER |
number |
number |
BOOLEAN |
boolean |
boolean |
DATE, TIMESTAMP, TEXT, EMAIL, URL, COLOR |
string |
string |
JSON, MAP |
Record<string, unknown> |
Record<string, unknown> |
EDITOR |
{ json: Record<string, unknown>; html: string; text: string; plain: string } |
Request와 동일 |
CATEGORY |
string |
Category |
FILE |
string |
ProjectFile |
REFERENCE |
string |
Record<string, unknown> |
| 그 외 / 인식되지 않는 타입 | unknown |
unknown |
배열 및 다국어 옵션
두 가지 Column 옵션은 생성되는 타입을 추가로 변형하며, 함께 사용할 수 있습니다.
| 옵션 | 효과 |
|---|---|
multiple |
타입을 Array<T>로 감쌉니다. |
localization |
타입을 Partial<Record<ProjectLanguage, T>>로 감쌉니다. |
// multiple + localization이 활성화된 TEXT Column
tags?: Partial<Record<ProjectLanguage, Array<string>>>
Predefined 탭
Predefined 탭에는 모든 Table의 Response 인터페이스에서 공통으로 참조하는 타입이 포함됩니다.
export type ProjectLanguage = 'ko' | 'en'
export interface Translation {
key: string
value: Partial<Record<ProjectLanguage, string>>
description: string | null
}
export interface Variable {
key: string
value: unknown
description: string | null
}
export interface FileMeta {
name: string
extension: string
lastModified: number
size: number
type: string
width: number | null
height: number | null
exif: Record<string, string> | null
}
export interface FileThumbnail {
path: string
presigned_url: string
size: string
width: number
height: number
}
export interface ProjectFile {
id: string
name: string
description: string | null
meta: FileMeta
s3_path: string
presigned_url: string
thumbnails: FileThumbnail[]
text_vision: string | null
description_generated: string | null
keywords: string[]
}
export interface Category {
id: string
name: string
}
ProjectLanguage는 현재 Project에 설정된 언어를 기준으로 유니언 타입으로 생성되므로 항상 Project의 실제 언어 설정을 반영합니다.
참조 타입에 마우스 올리기
Tables 탭에서 ProjectFile, Category, ProjectLanguage처럼 다른 타입을 참조하는 이름에는 밑줄이 표시됩니다. 해당 이름에 마우스를 올리거나 포커스를 두면 Predefined 탭으로 이동하지 않고도 툴팁으로 타입 정의를 확인할 수 있습니다.
생성된 타입 사용하기
정의를 프로젝트에 복사한 뒤, REST API fetch 응답의 타입으로 사용합니다.
const res = await fetch(
'https://api.onttle.com/v1/{projectId}/tables/blog-post/contents',
{ headers: { Authorization: `Bearer ${process.env.ONTTLE_API_KEY}` } },
)
const { list }: { list: BlogPostResponse[] } = await res.json()
console.log(list[0].data.title)
다음 단계
- 테이블 설계 — Column 설정이 생성되는 타입 정의에 어떻게 반영되는지 확인합니다.
- 응답 형식 — 목록 및 단일 항목 API 응답의 전체 구조를 확인합니다.
- OpenAPI 명세 — Contents 뿐 아니라 전체 API 타입을 생성하는 방법을 알아봅니다.