ESLint + TypeScript — typescript-eslint 규칙과 타입 인지 린팅
typescript-eslint은 ESLint에 TypeScript의 타입 정보를 활용한 고급 린팅 규칙 을 추가하는 플러그인입니다.
설치와 설정
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
Flat Config (ESLint 9+)
// eslint.config.mjs
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
);
타입 인지 린팅 (Type-Aware Linting)
타입 정보를 활용하는 규칙을 사용하려면 추가 설정이 필요합니다.
// eslint.config.mjs
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
);
주요 규칙 — 기본
no-unused-vars
// @typescript-eslint/no-unused-vars
// ❌ 사용하지 않는 변수
const unused = 42; // Error
// ✅ 언더스코어 접두사는 허용 (관례)
const _unused = 42; // OK
// ✅ 구조 분해에서 나머지만 사용
const { used, ...rest } = obj; // rest만 사용해도 OK
no-explicit-any
// @typescript-eslint/no-explicit-any
// ❌ 명시적 any 사용 금지
function parse(data: any) {} // Error
// ✅ unknown 사용
function parse(data: unknown) {} // OK
consistent-type-imports
// @typescript-eslint/consistent-type-imports
// ❌ 일반 import로 타입 가져오기
import { User } from './types';
// ✅ 타입 전용 import 명시
import type { User } from './types';
주요 규칙 — 타입 인지
타입 정보를 활용하는 규칙은 tsconfig.json의 타입 정보를 읽어서 동작합니다.
no-floating-promises
// @typescript-eslint/no-floating-promises
// ❌ Promise를 처리하지 않음
async function fetchData() { /* ... */ }
fetchData(); // Error: Promise가 처리되지 않음
// ✅ await 또는 .then()으로 처리
await fetchData();
// 또는
fetchData().catch(console.error);
// 또는 의도적으로 무시할 때
void fetchData();
공부하다 보니 이 규칙이 실무에서 가장 유용하더라고요. Promise를 처리하지 않으면 에러가 조용히 무시됩니다.
no-misused-promises
// @typescript-eslint/no-misused-promises
// ❌ async 함수를 boolean 위치에 사용
const isValid = async () => { /* ... */ };
if (isValid()) { /* ... */ } // Error: Promise는 항상 truthy
// ❌ 이벤트 핸들러에 async 함수 전달 (void 반환이어야 함)
// <button onClick={async () => { await save(); }}>저장</button>
await-thenable
// @typescript-eslint/await-thenable
// ❌ Promise가 아닌 값을 await
const value = 42;
const result = await value; // Error: 42는 thenable이 아님
// ✅ Promise만 await
const result2 = await Promise.resolve(42); // OK
no-unsafe-assignment / no-unsafe-call
// @typescript-eslint/no-unsafe-assignment
// ❌ any 타입 값 할당
const data: any = getExternalData();
const name = data.user.name; // Error: any 전파
// ✅ unknown으로 받고 타입 좁히기
const data2: unknown = getExternalData();
if (isUser(data2)) {
const name = data2.name; // OK
}
추천 설정 조합
// eslint.config.mjs — 실무 추천
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// 프로젝트에 맞게 조정
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
}],
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-floating-promises': 'error',
},
},
);
설정 프리셋 비교
| 프리셋 | 엄격도 | 타입 인지 |
|---|---|---|
recommended | 기본 | X |
recommendedTypeChecked | 기본 | O |
strict | 높음 | X |
strictTypeChecked | 높음 | O |
stylistic | 코드 스타일 | X |
stylisticTypeChecked | 코드 스타일 | O |
성능 고려사항
타입 인지 린팅은 타입 체커를 실행 하므로 일반 린팅보다 느립니다.
// 대규모 프로젝트에서 성능 최적화
{
"parserOptions": {
"projectService": true, // project보다 빠른 새 옵션
"tsconfigRootDir": "."
}
}
면접 포인트: "타입 인지 린팅을 쓰면 왜 느려지나요?"라고 물어보면, "ESLint가 AST만 보는 게 아니라 TypeScript 컴파일러의 타입 정보도 읽어야 하기 때문입니다"라고 답하면 됩니다.
정리
typescript-eslint은 TypeScript 전용 ESLint 규칙을 제공한다- 타입 인지 린팅은
no-floating-promises,await-thenable등 강력한 규칙을 포함한다 strict+TypeChecked조합이 가장 엄격한 설정이다- 타입 인지 린팅은 타입 체커를 실행하므로 성능 비용이 있다
projectService옵션으로 성능을 개선할 수 있다
댓글 로딩 중...