StackUp 프론트엔드의 TypeScript 타입 규약. 타입은 사용되는 레이어에 산다. 이름의 접미사가 책임 경계를 선언한다.
상위 컨텍스트 — coding-conventions.md (언어 공통 규약),
frontend/CLAUDE.md(FSD 구조) 적용 범위 —frontend/src/
- PascalCase + 의미 있는 접미사. 접미사가 타입의 책임·레이어를 신고한다.
I/THungarian prefix 금지 — TypeScript 컴파일러가type/interface를 충분히 구분한다.- 단방향 흐름:
Dto → Entity → Model → Props. 역방향 import 금지. - 전역
types/폴더 금지. 슬라이스 내부에서 시작, 진짜 공유될 때만 끌어올린다.
| 접미사 | 레이어 | 책임 | 예 |
|---|---|---|---|
XxxDto |
shared/api/ (OpenAPI 자동 생성) |
백엔드 wire format 스냅샷. 수정 금지 | SessionDto, UserDto |
XxxRequest / XxxPayload |
API 호출부, 이벤트 publisher | HTTP 요청 body, RabbitMQ 메시지 payload | CreateSessionRequest, ResumeAnalyzedPayload |
XxxResponse |
API 호출부 | HTTP 응답 raw shape (수동 정의 시) — 함수 반환에 사용 ✗ | LoginResponse |
Xxx (접미사 없음) |
domain/{slice}/model/ |
비즈니스 엔터티. Dto에서 매핑됨 | User, Session, Resume |
XxxResult |
도메인 / 유즈케이스 함수 반환 | 비즈니스 로직 출력 (HTTP 비종속) | AnalysisResult, ValidationResult |
XxxModel |
features/*/ui/, widgets/*/ui/ |
UI 표시 전용 가공 데이터 | SessionListItemModel, ServiceCardModel |
XxxProps |
컴포넌트 옆 | React props | ButtonProps, HomeHeroProps |
XxxState |
store / state machine | 명시적 상태 모델. 단발 useState shape 에 사용 ✗ |
AuthState, SessionMachineState |
XxxOptions |
함수·훅 설정 | 옵셔널 인자 묶음 | UseTypewriterOptions |
XxxId |
어디든 | branded identifier | type SessionId = number & { readonly __brand: 'SessionId' } |
[Backend OpenAPI]
│ openapi-typescript 자동 생성
▼
shared/api/generated.ts ── XxxDto
│ 매퍼 함수 (toUser, toSession)
▼
domain/{slice}/model/ ── Xxx (Entity)
│ feature / widget 에서 UI 가공
▼
features|widgets/*/ui/ ── XxxModel
│ props 로 주입
▼
React Component ── XxxProps
경계 규칙:
XxxDto는shared/api/밖으로 새지 않는다. UI · 도메인이 Dto 를 직접 import 하면 anti-corruption layer 가 무너진다.Xxx(Entity) 는domain/이 소유. features / widgets 는 read-only 로 참조한다.XxxModel은 슬라이스 내부에 머문다. 다른 슬라이스로 export 하지 않는다 — UI 표시 형태가 누수되면 변경 비용이 폭증한다.
type 기본값. interface 는 두 경우에만:
- 클래스가
implements할 때 (ErrorBoundary등) - declaration merging 필요 시 (외부 라이브러리 augmentation)
// 좋음
type SessionStatus = 'READY' | 'IN_PROGRESS' | 'COMPLETED';
type CreateSessionRequest = { userId: UserId; mode: SessionMode };
type AnalysisResult = { score: number; suggestions: string[] };
// 좋음 — implements 가 필요한 케이스
interface ErrorBoundaryProps { children: ReactNode; fallback: ReactNode }
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { ... }| 무엇 | 어디 |
|---|---|
| 컴포넌트 props (단일 사용) | {Component}.tsx 상단, export 안 함 |
| 외부에서도 import 되는 props | {Component}.types.ts |
| 도메인 엔터티 | domain/{slice}/model/types.ts |
슬라이스 내 XxxModel |
features/{slice}/model/types.ts 또는 ui/ 내부 |
API XxxDto |
shared/api/generated.ts (OpenAPI 재생성으로만 갱신) |
전역 src/types/ 폴더는 만들지 않는다. 슬라이스 내부에서 시작하고, 진짜 공유될 때만 끌어올린다.
타입을 shared/ 로 올리는 시점은 서로 다른 슬라이스 3곳 이상에서 동일한 shape 이 반복될 때. 그 전엔 슬라이스 안에 산다.
"언젠가 쓸지도 모르니 미리 shared 로" 는 항상 잘못된 추상화로 끝난다.
- ❌
XxxResponse를 함수 반환 타입으로 사용 —XxxResult로. - ❌ UI 컴포넌트가
SessionDto를 props 로 받음 —SessionListItemModel로 매핑. - ❌ 로컬
useState<{ ... }>shape 에XxxState이름 붙이고 export. - ❌
export type Props = { ... }같은 generic export —{Component}Props로. - ❌
src/types/또는src/shared/types/전역 폴더 (junk drawer 화). - ❌
IXxx,TXxxHungarian prefix. - ❌
Dto가features//widgets//domain/에서 import 되는 경우 — boundary 위반.