HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤎
프론트엔드 데브코스 5기 교육생
/
소인성팀
소인성팀
/
팀프로젝트-모모
팀프로젝트-모모
/
코딩 컨벤션
코딩 컨벤션
코딩 컨벤션

코딩 컨벤션

1. prettier2. eslint3. 네이밍4. 코드 스타일5. 폴더구조6. import 순서 규칙
 

1. prettier

{ "tabWidth": 2, "singleAttributePerLine": true, "bracketSameLine": true, "singleQuote": true, "endOfLine": "lf", "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "@storybook*", "@emotion*", "^react*", "^@*", "^[../]", "^[./]" ], "importOrderSortSpecifiers": true }

2. eslint

// .eslintrc.cjs module.exports = { root: true, env: { browser: true, es2021: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended-type-checked', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended', 'plugin:import/recommended', ], ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.ts', 'emotion.d.ts'], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 'latest', sourceType: 'module', project: true, tsconfigRootDir: __dirname, }, plugins: ['react-refresh', 'react', 'import'], rules: { 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], '@typescript-eslint/naming-convention': [ 'error', { selector: 'interface', format: ['PascalCase'], custom: { regex: '^I.*$|^.*Props$', match: true, }, }, { selector: 'variable', format: ['camelCase', 'PascalCase'], types: ['function'], }, { selector: 'variable', types: ['boolean'], format: ['PascalCase'], prefix: ['is', 'should', 'has', 'can', 'did', 'will'], }, { selector: 'variable', modifiers: ['destructured'], format: null, }, { selector: 'typeAlias', format: ['PascalCase'], suffix: ['Type'], }, ], 'react/jsx-key': 'error', 'no-unreachable': 'warn', }, settings: { 'import/resolver': { typescript: {}, }, }, };
 

3. 네이밍

분류
규칙
예시
eslint 강제 유무
상수
UPPER_SNAKE_CASE
const MAX_USERS = 10;
ㅤ
변수
camelCase boolean은 접두사 사용
let userName = 'JohnDoe'; let isActive = true; let hasLoggedIn = false;
✅
함수
camelCase, 동사+명사 boolean 반환은 'is' 접두사, api 요청 함수는 동사에 메서드, api 요청 함수에 명사 없을시 생략
const getUserProfile = () ⇒ { ... } const isUserActive = () ⇒ { ... } const async getPost = () ⇒ { … } const async login = () ⇒ { … }
⚠ 이름 규칙만
이벤트 핸들러
camelCase handle+명사+동사 props는 on 사용
const handleButtonClick = () ⇒ { ... } <button onClick={handleButtonClick}>Click me</button>
ㅤ
컴포넌트
PascalCase
const UserList = () ⇒ { ... }
ㅤ
type 별칭
PascalCase Type 접미사
type UserResponseType = ... type ButtonClickType = ...
✅
interface
PascalCase 컴포넌트에만 Props 접미사 그외 (스타일드컴포넌트포함) 모두 I 접두사
interface UserProps { ... } interface IUserOptions { ... }
✅
styled-component
PascalCase St 접두사
const StButton = styled.button <StButton>Save</StButton>
ㅤ
ㅤ
ㅤ
ㅤ
ㅤ
함수 인자 구조분해
규칙 없음 (모든 컨벤션 무시)
const createUser = ({ userName, userEmail }) ⇒ { ... }
ㅤ
 

4. 코드 스타일

// export를 붙이고 표현식을 사용해요 export const Component = () => { }
// return만 하는 조건문은 중괄호 없이 한줄로 작성해요 if(true) return; // return, break, throw 등에 대해서만 { } 없이 if(true) { state = newState }
// 명시적으로 import 하자 ! import { ReactElement, MouseEvent as ReactMouseEvent, ReactNode, RefObject, } from 'react';
 

5. 폴더구조

 
src/ |-- _redux/ | |-- slices/ | |-- store.ts # 여기에 Redux 스토어 설정을 초기화합니다. | `-- hooks.ts # Redux 관련 커스텀 훅을 정의합니다. |-- api | |-- _types/apiModels.ts # api Model 타입들을 정의합니다. | |-- apis.ts # method별 요청 api | `-- customAxios.ts # 커스텀한 AxiosInstance |-- assets/ # 로고, 파비콘등 이미지 파일 |-- components/ # 재사용 가능한 컴포넌트들을 포함합니다. | `-- _common/ # 재사용 공통 컴포넌트 |-- hooks/ # 공통 커스텀 훅 |-- pages/ # 라우트에 맞게 페이지 컴포넌트를 구성합니다. | |-- MainPage/ | |-- DetailPage/ | |-- ProfilePage/ | |-- LoginPage/ | |-- SignupPage/ | `-- ErrorPage/ |-- styles/ # 라우트에 맞게 페이지 컴포넌트를 구성합니다. | |-- emotion.d.ts # emotion 타입 설정파일 | |-- GlobalReset.tsx | `-- theme.ts/ # 디자인시스템 정의 |-- utils/ # 유틸리티 함수 등 공통적으로 사용될 수 있는 모듈들 |-- App.ts # 애플리케이션 레이아웃을 정의하는 최상위 컴포넌트 |-- index.ts # 애플리케이션 진입점 -- index.ts # 페이지 라우팅 설정 파일
 

6. import 순서 규칙

💡
아래에 위치할수록 본문과 가까워져서 중요도 높은 순으로 오름차순 정렬
  1. 나머지
  1. @storybook*
  1. emotion*
  1. react*
  1. @*
  1. ../
  1. ./