Files
claude-instructions/rules/frontend/code-style.md

3.0 KiB

코드 스타일 & 네이밍 컨벤션

Nuxt 4 + TypeScript strict 환경 기준 최종 업데이트: 2026-04-07


디렉토리 구조

my-nuxt-app/
├─ app/
│  ├─ assets/
│  ├─ components/          # PascalCase.vue
│  │   └─ ui/              # shadcn-vue 컴포넌트
│  ├─ composables/         # useXxx.ts
│  ├─ layouts/             # kebab-case.vue
│  ├─ middleware/          # kebab-case.ts
│  ├─ pages/               # kebab-case.vue
│  ├─ plugins/             # kebab-case.ts
│  ├─ stores/              # useXxxStore.ts
│  ├─ utils/               # camelCase.ts
│  ├─ app.vue
│  ├─ app.config.ts        # 테마/UI 등 공개 설정값
│  └─ error.vue
├─ server/
│  ├─ api/                 # kebab-case.ts
│  ├─ middleware/
│  └─ utils/
├─ shared/                 # 클라이언트/서버 공유 타입 및 유틸
├─ public/
├─ nuxt.config.ts
├─ tailwind.config.ts
└─ tsconfig.json

네이밍 컨벤션

파일명

파일 종류 규칙 예시
컴포넌트 PascalCase.vue UserProfile.vue
페이지 / 레이아웃 / 미들웨어 / 플러그인 kebab-case user-profile.vue
컴포저블 useXxx.ts useUserProfile.ts
유틸 함수 camelCase.ts formatDate.ts
Pinia store useXxxStore.ts useAuthStore.ts
API 라우트 kebab-case.ts user-profile.ts
테스트 파일 *.spec.ts / *.test.ts UserProfile.spec.ts

코드 내

대상 규칙 예시
변수 / 함수 camelCase const userName, function fetchUser()
컴포넌트명 PascalCase UserProfile, AppHeader
상수 UPPER_SNAKE_CASE const MAX_RETRY_COUNT = 3
타입 / 인터페이스 PascalCase interface UserProfile
// DO
const MAX_PAGE_SIZE = 100
const DEFAULT_LOCALE = 'ko'

// DON'T
const maxPageSize = 100    // 금지: 상수에 camelCase
const defaultLocale = 'ko' // 금지

TypeScript 엄격 모드

any 타입 사용 금지

any는 타입 안전성을 무력화한다. unknown 또는 명시적 타입을 사용한다.

// DON'T
async function fetchUser(id: any): Promise<any> {
  return await $fetch(`/api/users/${id}`)
}

// DO
async function fetchUser(id: string): Promise<User> {
  return await $fetch<User>(`/api/users/${id}`)
}

// unknown 사용 시 타입 좁히기
function parseResponse(raw: unknown): User {
  if (!isUser(raw)) throw new Error('유효하지 않은 응답입니다.')
  return raw
}

Props 타입 명시

<script setup lang="ts">
// DO: interface로 분리 선언
interface Props {
  title: string
  count: number
  variant?: 'primary' | 'secondary'
}
const props = withDefaults(defineProps<Props>(), {
  variant: 'primary',
})

// DON'T: 타입 없는 defineProps
// const props = defineProps(['title', 'count'])
</script>