Skip to Content
WebTypeScriptTypeScript02. 프로젝트 준비: Vite vanilla-ts로 시작하기

이번 편의 결과물: 빈 폴더에서 expense-tracker/ 프로젝트가 생성되고, npm run dev로 접속한 브라우저 화면에 “가계부 준비 완료”가 표시됩니다. · 다루는 개념: Node 22/Vite 8 확인, npm create vite로 vanilla-ts 프로젝트 생성, 기본 tsconfig.json 읽기, tsc --noEmitvite dev의 차이

이 편에서 만드는 파일

expense-tracker/ (+, 새 프로젝트) ├── index.html (+) ├── package.json (+) ├── tsconfig.json (+) ├── public/ │ └── vite.svg (+) └── src/ ├── main.ts (+) ├── style.css (+) └── vite-env.d.ts (+)

개념 정리

Node 22 / Vite 8 확인

이 과목은 Node.js 22 LTS와 Vite 8을 기준으로 진행합니다. 프로젝트를 만들기 전에 버전을 확인합니다.

도구요구 버전확인 명령
Node.js22 이상(LTS)node -v
npmNode.js에 포함된 버전npm -v

npm create vite로 vanilla-ts 템플릿 생성

npm create vite@latest는 다양한 템플릿 중 하나를 골라 프로젝트 뼈대를 만들어 주는 공식 스캐폴딩 명령입니다. --template vanilla-ts는 프레임워크 없이 TypeScript만 설정된 템플릿을 의미합니다.

템플릿 이름내용
vanilla프레임워크 없는 순수 JavaScript
vanilla-ts프레임워크 없는 순수 TypeScript(이 과목에서 사용)
react, react-tsReact(JS/TS)

기본 tsconfig.json 읽기

npm create vite가 생성하는 tsconfig.json은 아래 옵션들을 기본으로 포함합니다.

옵션의미
target컴파일 결과가 어떤 JS 문법 버전으로 변환될지
module어떤 모듈 문법(import/export)으로 변환될지
strict엄격한 타입 검사 규칙 묶음을 모두 켠다(16편에서 하위 옵션을 하나씩 다룸)
noEmit이 설정으로 직접 JS 파일을 만들지 않는다(번들링은 Vite가 담당)
moduleResolution모듈 경로를 해석하는 방식. bundler는 Vite 같은 번들러 환경에 맞춘 방식
include타입 검사 대상 폴더(src)

TypeScript 7부터 strict는 명시하지 않아도 기본값이 참(true)이지만, Vite 템플릿은 설정 의도를 코드로 남기기 위해 여전히 명시적으로 적어 둡니다.

tsc —noEmit과 vite dev의 차이

명령하는 일타입 오류가 있어도
npm run dev(vite)코드를 변환해 브라우저에 즉시 반영(빠른 개발 서버)화면은 계속 뜬다(타입 검사를 하지 않음)
npx tsc --noEmit파일을 생성하지 않고 타입만 검사오류 목록을 출력하고 끝난다(화면과 무관)

vite dev는 속도를 위해 타입 검사를 건너뛰고 코드 변환만 합니다. 타입 오류가 있어도 화면은 그대로 뜰 수 있으므로, 타입 오류 여부는 tsc --noEmit으로 따로 확인해야 합니다.

실습

1. 버전 확인

node -v npm -v

2. 프로젝트 생성

npm create vite@latest expense-tracker -- --template vanilla-ts cd expense-tracker npm install

생성된 package.json의 스크립트는 다음과 같습니다.

// expense-tracker/package.json { "name": "expense-tracker", "private": true, "version": "0.0.1", "type": "module", "scripts": { "dev": "vite", "build": "tsc -b && vite build", "preview": "vite preview" }, "devDependencies": { "typescript": "~7.0.0", "vite": "^8.0.0" } }

build 스크립트는 지금은 tsc -b(타입 검사 겸 빌드 참조 확인)와 vite build(번들링)를 한 번에 실행합니다. 이 둘을 분리하는 작업은 18편에서 다룹니다.

생성된 tsconfig.json을 확인합니다.

// expense-tracker/tsconfig.json { "compilerOptions": { "target": "ES2023", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ES2023", "DOM", "DOM.Iterable"], "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "isolatedModules": true, "moduleDetection": "force", "noEmit": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, "include": ["src"] }

3. 기본 화면 정리

템플릿이 만든 src/counter.ts, src/typescript.svg는 이 과목에서 쓰지 않으므로 지웁니다.

rm src/counter.ts src/typescript.svg

index.html의 제목을 정리합니다.

<!-- expense-tracker/index.html --> <!doctype html> <html lang="ko"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>expense-tracker</title> </head> <body> <div id="app"></div> <script type="module" src="/src/main.ts"></script> </body> </html>

src/main.ts를 아래 내용으로 통째로 바꿉니다.

// expense-tracker/src/main.ts import './style.css' const app = document.querySelector<HTMLDivElement>('#app') if (app) { app.innerHTML = ` <main> <h1>가계부</h1> <p>가계부 준비 완료</p> </main> ` }

document.querySelector<HTMLDivElement>('#app')의 꺾쇠 부분은 반환 타입을 HTMLDivElement로 좁혀 주는 문법입니다. 이 문법 자체(제네릭)는 08편에서 자세히 다루고, 지금은 “#appdiv 요소라는 것을 TypeScript에 알려준다” 정도로만 이해하면 됩니다. appnull일 수도 있으므로 if (app)으로 확인한 뒤에만 innerHTML을 사용합니다.

src/style.css도 내용을 정리합니다.

/* expense-tracker/src/style.css */ body { margin: 0; font-family: system-ui, sans-serif; background-color: #f8fafc; color: #0f172a; } main { max-width: 640px; margin: 0 auto; padding: 2rem 1rem; }

src/vite-env.d.ts는 템플릿이 만든 그대로 둡니다.

// expense-tracker/src/vite-env.d.ts /// <reference types="vite/client" />

4. 개발 서버 실행

npm run dev

5. 타입 체크만 따로 실행

npx tsc --noEmit
(출력 없음 — 타입 오류가 없으면 아무것도 출력되지 않고 종료됩니다)

확인

  • 터미널에 나온 주소(대개 http://localhost:5173)로 접속하면 “가계부”라는 제목과 “가계부 준비 완료” 문구가 보입니다.
  • 브라우저 개발자 도구 콘솔에 빨간 오류가 없습니다.
  • npx tsc --noEmit을 실행해도 아무 오류가 출력되지 않습니다(타입 오류 없음을 의미).

직접 해보기

  1. index.html<title>을 다른 문자열로 바꾸고 새로고침 없이 브라우저 탭 제목이 바로 바뀌는지 확인합니다.
  2. main.ts<p>가계부 준비 완료</p>를 지우고 저장한 뒤, 개발 서버를 다시 켜지 않아도 화면이 즉시 바뀌는지(핫 모듈 교체) 확인하고 원래대로 되돌립니다.

정답 보기

npm run dev로 띄운 Vite 개발 서버는 파일을 저장할 때마다 변경 사항을 자동으로 감지해 브라우저에 반영합니다(핫 모듈 교체). 개발 서버를 껐다 켤 필요 없이 저장만 하면 화면이 즉시 갱신됩니다.

자주 하는 실수

증상원인고치는 법
npm create vite 명령 후 프레임워크 선택 화면이 나옴--template vanilla-ts를 빠뜨림명령 뒤에 -- --template vanilla-ts를 정확히 붙인다
npm run dev 실행 시 포트 오류다른 프로그램이 같은 포트를 이미 사용 중터미널에 안내된 대체 포트로 접속하거나 기존 프로세스를 종료한다
화면은 정상인데 타입 오류를 놓침vite dev만 보고 tsc --noEmit을 실행하지 않음코드를 크게 바꿀 때마다 npx tsc --noEmit을 따로 실행하는 습관을 들인다

확인 문제

문제 14지선다
expense-tracker 프로젝트를 만드는 정확한 명령은?
문제 24지선다
tsconfig.json의 noEmit 옵션이 켜져 있는 이유는?
문제 34지선다
npm run dev와 npx tsc --noEmit의 차이로 옳은 것은?
문제 44지선다
document.querySelector<HTMLDivElement>('#app')처럼 반환 타입을 지정하는 이유는?

참고 자료

Last updated on