1.5 개발 도구 설정
코드를 올바르게 작성하는 것도 중요하지만, 좋은 개발 도구를 갖추면 실수를 훨씬 줄일 수 있다. TypeScript는 IDE와의 깊은 통합을 통해 자동완성, 즉각적인 오류 표시, 안전한 리팩토링을 제공한다. 이 장에서는 VS Code 최적화 설정, ESLint로 코드 품질 유지, Prettier로 코드 스타일 통일, 그리고 에러 코드를 읽는 법까지 개발 환경 전반을 다룬다.
VS Code TypeScript 지원
TypeScript는 Microsoft가 만들었고, VS Code 역시 Microsoft가 만들었다. 이 두 도구는 처음부터 함께 설계되었다. VS Code는 별도 플러그인 없이도 TypeScript를 완벽하게 지원한다.
내장 TypeScript 서버 (tsserver)
VS Code는 내부적으로 tsserver라는 TypeScript 언어 서버를 실행한다. tsserver가 백그라운드에서 코드를 분석하고 다음 기능을 제공한다.
- IntelliSense: 타입 정보를 기반으로 객체의 속성, 함수의 매개변수, 반환 타입을 자동으로 제안한다
- 즉시 오류 표시: 파일을 저장하지 않아도 코드를 작성하는 순간 빨간 밑줄로 오류를 표시한다
- 호버 타입 정보: 변수나 함수 위에 마우스를 올리면 타입 정보가 표시된다
- Go to Definition:
F12또는Ctrl+클릭으로 함수/타입 정의로 즉시 이동한다 - Find All References:
Shift+F12로 함수나 타입이 사용된 모든 위치를 찾는다 - Rename Symbol:
F2로 변수/함수명을 안전하게 일괄 변경한다
VS Code TypeScript 버전 전환
프로젝트에 로컬로 설치된 TypeScript 버전과 VS Code 내장 TypeScript 버전이 다를 수 있다. 프로젝트의 TypeScript 버전을 사용하도록 설정하는 것이 권장된다.
.ts파일을 열고Ctrl+Shift+P(명령 팔레트 열기)- "TypeScript: Select TypeScript Version" 검색
- "Use Workspace Version" 선택
이 설정은 .vscode/settings.json에 저장된다.
{
"typescript.tsdk": "node_modules/typescript/lib"
}
유용한 VS Code 설정 (settings.json)
.vscode/settings.json에 프로젝트별 VS Code 설정을 추가한다. 팀원이 동일한 설정을 사용하도록 이 파일을 Git에 커밋한다.
{
// TypeScript 버전 — 프로젝트 로컬 버전 사용
"typescript.tsdk": "node_modules/typescript/lib",
// 자동 임포트 제안 활성화
"typescript.suggest.autoImports": true,
// 파일 이동 시 임포트 경로 자동 업데이트
"typescript.updateImportsOnFileMove.enabled": "always",
// 인레이 힌트 — 추론된 타입을 코드에 직접 표시
"typescript.inlayHints.parameterNames.enabled": "literals",
"typescript.inlayHints.variableTypes.enabled": false,
"typescript.inlayHints.returnTypes.enabled": true,
"typescript.inlayHints.functionLikeReturnTypes.enabled": true,
// 저장 시 자동 포맷팅 (Prettier 사용 시)
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
// 저장 시 ESLint 자동 수정
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
인레이 힌트 (Inlay Hints)
인레이 힌트는 코드에 타입 정보를 반투명하게 오버레이로 표시하는 기능이다. 타입 어노테이션 없이도 어떤 타입이 추론되는지 에디터에서 바로 볼 수 있다.
// inlayHints.parameterNames.enabled: "all" 설정 시 보이는 것
const result = arr.reduce(/*accumulator:*/ (acc, /*currentValue:*/ cur) => acc + cur, 0);
// inlayHints.returnTypes.enabled: true 설정 시
function add(a: number, b: number) /*: number*/ {
return a + b;
}
ESLint + typescript-eslint
TypeScript 컴파일러는 타입 오류를 잡는다. ESLint는 그 외의 코드 품질 문제를 잡는다. 예를 들어 사용하지 않는 변수, 불필요한 any 타입 사용, 잠재적인 버그 패턴 등이다. TypeScript 프로젝트에서는 typescript-eslint를 함께 사용한다.
설치
npm install --save-dev eslint @eslint/js typescript-eslint
eslint.config.mjs 설정 (ESLint v9 Flat Config)
ESLint v9부터는 eslint.config.mjs 파일을 사용한다(Flat Config 방식).
// eslint.config.mjs
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
// JavaScript 기본 권장 규칙
eslint.configs.recommended,
// TypeScript 권장 규칙
...tseslint.configs.recommended,
// 프로젝트 커스텀 규칙
{
rules: {
// any 타입 사용 시 경고 (에러 대신 경고로 설정)
'@typescript-eslint/no-explicit-any': 'warn',
// 사용하지 않는 변수 에러 처리
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' }
],
// 빈 함수 허용
'@typescript-eslint/no-empty-function': 'off',
},
}
);
argsIgnorePattern: '^_'는 이름이 _로 시작하는 변수는 미사용이어도 무시한다. 의도적으로 사용하지 않는 매개변수를 _name처럼 표시하는 관례와 호환된다.
@typescript-eslint/recommended 주요 규칙
tseslint.configs.recommended에 포함된 대표적인 규칙들:
| 규칙 | 설명 |
|---|---|
no-explicit-any | any 타입 사용 금지/경고 |
no-unused-vars | 사용하지 않는 변수 오류 |
no-non-null-assertion | ! 단언 연산자 금지 |
prefer-as-const | as const 사용 권장 |
ban-types | Object, String 등 래퍼 타입 사용 금지 |
no-inferrable-types | 추론 가능한 곳에 타입 명시 금지 |
package.json 스크립트 추가
{
"scripts": {
"lint": "eslint src",
"lint:fix": "eslint src --fix"
}
}
npm run lint # 오류 목록 출력
npm run lint:fix # 자동 수정 가능한 오류 수정
Prettier 연동
ESLint가 코드 품질을 잡는다면, Prettier는 코드 스타일(들여쓰기, 따옴표, 세미콜론 등)을 통일한다. 팀원 모두가 동일한 포맷으로 코드를 작성하게 된다.
설치
npm install --save-dev prettier eslint-config-prettier
prettier: 코드 포맷터eslint-config-prettier: Prettier와 충돌하는 ESLint 규칙을 비활성화
.prettierrc 설정
프로젝트 루트에 .prettierrc 파일을 생성한다.
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "lf"
}
| 옵션 | 기본값 | 설명 |
|---|---|---|
semi | true | 세미콜론 추가 |
trailingComma | "all" | 마지막 항목 뒤 쉼표 |
singleQuote | false | 작은따옴표 사용 |
printWidth | 80 | 줄 최대 길이 |
tabWidth | 2 | 들여쓰기 칸 수 |
endOfLine | "lf" | 줄바꿈 문자 (LF/CRLF) |
ESLint와 Prettier 통합
eslint.config.mjs에 eslint-config-prettier를 추가한다. 반드시 마지막에 위치해야 한다.
// eslint.config.mjs
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
},
},
// 마지막에 추가 — Prettier와 충돌하는 규칙을 모두 비활성화
eslintConfigPrettier,
);
package.json에 포맷팅 스크립트 추가
{
"scripts": {
"format": "prettier --write src",
"format:check": "prettier --check src"
}
}
npm run format # 모든 파일 자동 포맷팅
npm run format:check # 포맷팅 필요 여부만 확인 (CI에서 사용)
.editorconfig 설정
.editorconfig는 에디터 간 기본 코딩 스타일을 통일한다. VS Code, IntelliJ, Vim 등 다양한 에디터가 이 파일을 인식한다. Prettier와 함께 사용하면 에디터 수준의 기본 설정도 통일된다.
프로젝트 루트에 .editorconfig 파일을 생성한다.
# .editorconfig
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
VS Code에서 .editorconfig를 적용하려면 "EditorConfig for VS Code" 확장 프로그램을 설치한다.
TypeScript 에러 코드 읽는 법
TypeScript 에러 메시지는 처음에 낯설게 느껴지지만 패턴을 이해하면 빠르게 해석할 수 있다.
에러 메시지 구조
src/index.ts:10:20 - error TS2345: Argument of type 'string' is not assignable
to parameter of type 'number'.
src/index.ts:10:20— 파일 경로, 줄 번호(10), 열 번호(20)error— 심각도 (error / warning)TS2345— TypeScript 에러 코드- 나머지 — 사람이 읽을 수 있는 설명
자주 만나는 에러 코드
TS2322 — Type 'X' is not assignable to type 'Y'
가장 자주 만나는 에러. 타입이 맞지 않는 값을 할당하려 할 때 발생한다.
const age: number = "30";
// TS2322: Type 'string' is not assignable to type 'number'.
TS2345 — Argument of type 'X' is not assignable to parameter of type 'Y'
함수에 잘못된 타입의 인수를 전달할 때 발생한다.
function greet(name: string): void { }
greet(42);
// TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
TS2339 — Property 'X' does not exist on type 'Y'
객체에 존재하지 않는 속성에 접근할 때 발생한다.
const user = { name: "Alice" };
console.log(user.age);
// TS2339: Property 'age' does not exist on type '{ name: string; }'.
TS2531 — Object is possibly 'null'
strictNullChecks가 켜진 상태에서 null일 수 있는 값에 접근할 때 발생한다.
const element = document.getElementById("app");
element.textContent = "Hello";
// TS2531: Object is possibly 'null'.
// 해결
element?.textContent = "Hello"; // 옵셔널 체이닝
// 또는
if (element) element.textContent = "Hello";
TS7006 — Parameter 'X' implicitly has an 'any' type
strict 모드에서 함수 매개변수에 타입을 명시하지 않으면 발생한다.
function process(data) { // data의 타입 없음
// TS7006: Parameter 'data' implicitly has an 'any' type.
}
// 해결
function process(data: string) { }
TS2304 — Cannot find name 'X'
선언되지 않은 변수나 타입을 사용할 때 발생한다.
console.log(undeclaredVariable);
// TS2304: Cannot find name 'undeclaredVariable'.
실전 예제: 완전한 개발 환경 세팅 단계별 가이드
새 TypeScript 프로젝트의 개발 환경을 처음부터 구성하는 전체 과정이다.
1단계: 프로젝트 초기화
mkdir my-typescript-app
cd my-typescript-app
npm init -y
mkdir src
2단계: 핵심 패키지 설치
# TypeScript 및 실행 도구
npm install --save-dev typescript tsx @types/node
# ESLint 및 TypeScript 플러그인
npm install --save-dev eslint @eslint/js typescript-eslint
# Prettier 및 ESLint 통합
npm install --save-dev prettier eslint-config-prettier
3단계: tsconfig.json 설정
npx tsc --init
tsconfig.json을 다음과 같이 수정한다.
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"lib": ["ES2022"],
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
4단계: ESLint 설정
// eslint.config.mjs
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},
eslintConfigPrettier,
);
5단계: Prettier 설정
// .prettierrc
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "lf"
}
6단계: VS Code 설정
// .vscode/settings.json
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.inlayHints.parameterNames.enabled": "literals",
"typescript.inlayHints.returnTypes.enabled": true
}
7단계: .editorconfig 설정
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
8단계: .gitignore 추가
node_modules/
dist/
*.js.map
.DS_Store
9단계: package.json 스크립트 추가
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "npm run type-check && tsc",
"start": "node dist/index.js",
"type-check": "tsc --noEmit",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"format": "prettier --write src",
"format:check": "prettier --check src"
}
}
10단계: 첫 소스 파일 작성 및 동작 확인
// src/index.ts
interface User {
id: number;
name: string;
email: string;
}
function createWelcomeMessage(user: User): string {
return `환영합니다, ${user.name}! (${user.email})`;
}
const user: User = {
id: 1,
name: '개발자',
email: 'dev@example.com',
};
console.log(createWelcomeMessage(user));
npm run dev
# 환영합니다, 개발자! (dev@example.com)
npm run type-check
# 타입 오류 없음
npm run lint
# 린트 오류 없음
고수 팁
// @ts-expect-error vs // @ts-ignore
두 주석 모두 다음 줄의 TypeScript 오류를 억제한다. 그러나 중요한 차이가 있다.
// @ts-ignore — 오류가 있든 없든 무조건 억제
// @ts-ignore
const x: number = "hello"; // 오류 억제됨
// @ts-expect-error — 오류가 있을 때만 억제, 오류가 없으면 자체적으로 오류 발생
// @ts-expect-error
const y: number = "world"; // 오류 억제됨
// @ts-expect-error를 붙였는데 오류가 없으면?
// @ts-expect-error
const z: number = 42; // 오류: Unused '@ts-expect-error' directive.
@ts-expect-error가 더 안전하다. 나중에 코드가 수정되어 오류가 사라졌을 때 @ts-expect-error 주석 자체가 오류가 되어 알려준다. 반면 @ts-ignore는 오류가 사라져도 조용히 남아 있다.
실무에서는 @ts-ignore보다 @ts-expect-error를 사용하자. 그리고 왜 오류를 억제하는지 이유를 주석으로 반드시 남긴다.
// @ts-expect-error — 외부 라이브러리 타입 정의 오류, 버전 업데이트 후 제거 예정
someLibrary.undocumentedMethod();
"Go to Definition"으로 내장 타입 탐색
Ctrl+클릭 (또는 F12)으로 TypeScript 내장 타입의 정의로 이동할 수 있다. Array, Promise, Map 같은 내장 타입의 메서드와 속성이 어떻게 정의되어 있는지 직접 볼 수 있다.
예를 들어 Array.prototype.map의 타입 정의로 이동하면 다음과 같은 코드를 볼 수 있다.
// lib.es5.d.ts (TypeScript 내장 타입 정의)
interface Array<T> {
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
}
이 타입 정의를 보면 map이 제네릭을 어떻게 활용하는지, 콜백 함수의 매개변수가 무엇인지 정확히 알 수 있다. 라이브러리 문서를 찾아보는 것보다 더 정확한 정보를 얻을 수 있다.
팀 프로젝트에서 VS Code 확장 프로그램 공유
.vscode/extensions.json에 프로젝트 권장 확장 프로그램 목록을 추가하면, 팀원이 프로젝트를 열었을 때 VS Code가 설치를 자동으로 제안한다.
// .vscode/extensions.json
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"usernamehw.errorlens"
]
}
정리
| 도구 | 역할 | 설정 파일 |
|---|---|---|
| VS Code tsserver | 타입 검사, 자동완성, 에러 표시 | .vscode/settings.json |
| ESLint + typescript-eslint | 코드 품질, 안티패턴 감지 | eslint.config.mjs |
| Prettier | 코드 스타일 통일 | .prettierrc |
| eslint-config-prettier | ESLint + Prettier 충돌 방지 | eslint.config.mjs 마지막 |
| .editorconfig | 에디터 기본 설정 통일 | .editorconfig |
| 에러 코드 | 의미 |
|---|---|
| TS2322 | 타입 불일치 할당 |
| TS2345 | 함수 인수 타입 불일치 |
| TS2339 | 존재하지 않는 속성 접근 |
| TS2531 | null/undefined 가능성 |
| TS7006 | 암묵적 any 타입 (매개변수) |
| TS2304 | 선언되지 않은 이름 사용 |
다음 장에서는 TypeScript의 기본 타입 시스템을 본격적으로 배운다. string, number, boolean부터 시작해 union, intersection, 리터럴 타입까지 TypeScript 타입의 기초를 다진다.