프로필 로고
2026-04-09

ESLint

ESLint가 코드를 AST로 변환해 문법 오류와 스타일 위반을 검사하는 원리, React·TypeScript 플러그인과 실무 규칙, Prettier와의 역할 분리, AI 코드 생성 시대의 가드레일 역할

  • ESLint
  • AST
  • React

ESLint는 코드의 정확성과 일관성을 자동으로 지켜주는 도구이며, AI가 코드를 대량 생산하는 시대일수록 품질의 마지노선 역할을 한다.

ESLint란 무엇인가

  1. 자바스크립트는 동적 타입 언어로, 실행하기 전까지 오류를 알기 어려운 특성이 있다.

  2. 그래서 개발자가 실수로 선언하지 않은 변수를 쓰거나, 사용하지 않는 변수를 남겨도 실행 시점에서야 문제가 드러난다.

  3. 또한 팀 단위 협업에서는 사람마다 코드 스타일이 달라, 따옴표 종류나 세미콜론 사용 같은 사소한 부분에서 충돌이 자주 발생했다.

  4. 이런 문제를 해결하기 위해 등장한 것이 정적 분석 도구이며, 그중 가장 널리 쓰이는 것이 ESLint이다.

  5. ESLint는 코드를 실행하지 않고도 문법적 오류와 잠재적 버그, 스타일 위반을 미리 잡아주는 린터(Linter)이다.

  6. 즉, 코드를 작성하는 순간 “이 코드는 규칙에 어긋난다”라고 알려주는 자동 코드 검사기 역할을 한다.

ESLint의 작동 방식

  1. ESLint는 코드를 문자열이 아닌 AST(Abstract Syntax Tree, 추상 구문 트리)로 변환해 분석한다.

  2. 즉, 코드를 단순 텍스트가 아니라 구조로 이해하기 때문에 “이 변수는 선언만 되고 사용되지 않았다” 같은 의미 단위 검사가 가능하다.

  3. 설정 파일(.eslintrc, eslint.config.js 등)에 어떤 규칙을 적용할지 정의하면, 그 규칙대로 코드를 검사한다.

  4. 규칙 위반 시 error, warn, off 세 가지 수준으로 경고를 표시한다.

React에서 ESLint 사용하기

  1. React 프로젝트에서는 기본 ESLint 규칙만으로는 부족하므로, React 전용 플러그인을 함께 사용한다.

  2. 대표적으로 eslint-plugin-react, eslint-plugin-react-hooks, @typescript-eslint/eslint-plugin이 자주 쓰인다.

  3. ViteCreate React App 같은 도구는 설치 시 기본 ESLint 설정을 함께 제공한다.

  4. 설정 파일은 보통 아래와 같은 구조로 작성한다.

    // eslint.config.js
    export default [
      {
        plugins: {
          react, // React 관련 규칙을 사용하기 위한 플러그인 등록
          'react-hooks': reactHooks, // React Hooks 규칙을 사용하기 위한 플러그인 등록
        },
        rules: {
          'react/jsx-uses-react': 'off', // React 17+ 에서는 JSX 사용 시 React import가 불필요하므로 끔
          'react/react-in-jsx-scope': 'off', // 위와 같은 이유로 'React가 스코프에 있어야 한다'는 규칙도 끔
          'react-hooks/rules-of-hooks': 'error', // 훅을 조건문/반복문 안에서 호출하면 에러 처리 (호출 순서 보장)
          'react-hooks/exhaustive-deps': 'warn', // useEffect 등의 의존성 배열 누락 시 경고 표시
        },
      },
    ];
  5. 위 설정에서 react/react-in-jsx-scope를 끈 이유는, React 17 이후로 JSX를 쓰기 위해 import React를 명시하지 않아도 되기 때문이다.

실무에서 자주 쓰는 규칙

  1. 첫 번째로 react-hooks/rules-of-hooks는 훅을 조건문이나 반복문 안에서 호출하지 못하게 막는다.

  2. 이 규칙은 React의 Hook 호출 순서 보장을 위해 반드시 error 수준으로 둔다.

    // 잘못된 예 - 조건부 훅 호출
    function Component({ flag }) {
      if (flag) {
        const [count, setCount] = useState(0); // ESLint error
      }
    }
  3. 두 번째로 react-hooks/exhaustive-depsuseEffect 같은 훅의 의존성 배열이 누락되지 않았는지 검사한다.

  4. 이 규칙 덕분에 “의존성에 빠진 변수 때문에 발생하는 stale closure” 같은 버그를 사전에 막을 수 있다.

    useEffect(() => {
      fetchUser(userId);
    }, [userId]); // userId가 빠지면 ESLint가 경고함
  5. 세 번째로 no-unused-vars는 사용되지 않는 변수를 잡아낸다.

  6. TypeScript 환경에서는 동일한 역할을 하는 @typescript-eslint/no-unused-vars를 대신 쓰는 것이 정확하다.

  7. 네 번째로 react/jsx-key는 리스트 렌더링 시 key 속성을 빠뜨리지 않도록 강제한다.

    items.map((item) => <li key={item.id}>{item.name}</li>);
  8. 다섯 번째로 no-console은 배포 코드에 console.log가 남는 것을 방지한다.

  9. 보통 개발 중에는 warn, 배포 직전에는 error로 단계적 운영을 한다.

Prettier와의 관계

  1. ESLint는 코드의 “정확성”을 검사하고, Prettier는 코드의 “모양”을 정리한다.

  2. 두 도구의 역할이 겹치는 부분이 있으므로, eslint-config-prettier를 함께 설치해 충돌을 막는 것이 일반적이다.

  3. 즉, 포맷팅은 Prettier에 맡기고, 논리적 검사만 ESLint가 담당하도록 분리한다.

AI 시대에 Lint의 중요성

  1. 최근에는 ChatGPT, Claude 같은 AI 도구가 코드를 직접 작성해주는 시대가 되었다.

  2. 그래서 “이제는 린트가 필요 없는 것 아닌가?”라는 의문이 생길 수 있다.

  3. 그러나 오히려 AI 시대에 린트의 중요성은 더욱 커졌다.

  4. 첫째, AI가 만든 코드는 그럴듯해 보이지만 잘못된 패턴이나 사용하지 않는 import, 잘못된 의존성 배열 같은 미세한 오류를 포함하기 쉽다.

  5. 사람이 일일이 검수하기 어려운 양의 코드가 생성되므로, 자동화된 검사가 필수가 된다.

  6. 둘째, AI는 프로젝트의 컨벤션을 완벽히 따르지 않을 수 있다.

  7. ESLint 설정은 “이 프로젝트는 이런 규칙을 따른다”라는 명시적 기준이 되어, AI 결과물을 프로젝트 스타일로 정렬시키는 가드레일 역할을 한다.

  8. 셋째, AI 코드 생성의 신뢰성을 검증하는 첫 단계가 정적 분석이다.

  9. 테스트 코드가 잡지 못하는 영역, 예컨대 타입 추론 오류나 React 훅 규칙 위반을 사전에 차단하는 역할을 한다.

  10. 넷째, AI에게 더 좋은 코드를 요구하기 위한 피드백 루프로도 쓰인다.

  11. 린트 결과를 다시 AI에게 입력하면, AI가 스스로 코드를 수정해 품질을 점진적으로 높일 수 있다.

  12. 결국 AI가 코드를 “쓰는” 시대일수록, 사람은 “검증과 기준 설정”에 집중해야 하며, 그 중심에 ESLint 같은 정적 분석 도구가 존재한다.