plogger

Vue 3 + TypeScript 실전 설정 가이드

Vite로 Vue 3 + TypeScript 프로젝트 생성

npm create vite@latest my-app -- --template vue-ts
cd my-app && npm install

defineProps에 타입 지정

<script setup lang="ts">
// 방법 1: 타입 기반 (권장)
interface Props {
  title: string
  count?: number
  tags: string[]
}
const props = defineProps<Props>()

// 방법 2: 기본값 포함
const props = withDefaults(defineProps<Props>(), {
  count: 0,
  tags: () => [],
})
</script>

defineEmits에 타입 지정

<script setup lang="ts">
const emit = defineEmits<{
  submit: [payload: { name: string; age: number }]
  cancel: []
}>()

emit('submit', { name: 'Hoon', age: 30 })
</script>

ref 타입 지정

import { ref } from 'vue'

const count = ref<number>(0)
const user = ref<{ name: string; age: number } | null>(null)
const items = ref<string[]>([])

reactive 타입 지정

import { reactive } from 'vue'

interface User {
  name: string
  age: number
  email: string
}

const user = reactive<User>({
  name: 'Hoon',
  age: 30,
  email: 'hoon@example.com',
})

computed 타입 지정

import { ref, computed } from 'vue'

const count = ref(0)
const doubleCount = computed<number>(() => count.value * 2)

Template Ref 타입 지정

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const inputEl = ref<HTMLInputElement | null>(null)

onMounted(() => {
  inputEl.value?.focus()
})
</script>

<template>
  <input ref="inputEl" />
</template>

API 응답 타입 정의

// types/api.ts
export interface Post {
  id: number
  title: string
  content: string
  createdAt: string
}

// composables/usePost.ts
import type { Post } from '@/types/api'

async function fetchPost(id: number): Promise<Post> {
  const res = await fetch(`/api/posts/${id}`)
  return res.json() as Promise<Post>
}

tsconfig.json 권장 설정

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "bundler",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}