TestForge | Aidevops | 📊 Plogger ✍️ Blog 📚 Docs
plogger

AI DevOps Korea

Turn AI service development and operations into one improvement loop

Aidevops.kr covers LLMOps, RAG, agents, observability, evaluation, and cost-performance optimization for production AI services.

Vue 3 + TypeScript Design Guide

· Updated Apr 16
Vue 3 + TypeScript Design Guide diagram
Visual guide to the key flow, architecture, and decision points covered in this post.
The Vue 3 and TypeScript combination is strong when you want clearer component contracts and safer reusable units with the Composition API. But if you split types too aggressively, the code can become harder to read. What matters is not the amount of typing, but building a type model with clear boundaries.

A standard template is enough to start

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

Early in a project, it is usually more important to build the habit of separating components from domain models under strict mode than to keep expanding configuration.

Props and emits are the core of the component contract

<script setup lang="ts">
interface Props {
  title: string
  disabled?: boolean
}

const props = defineProps<Props>()

const emit = defineEmits<{
  submit: [id: number]
}>()
</script>

This style makes the contract between parent and child explicit in the type system. It is especially useful because event payloads become clear, which makes interaction flow easier to read.

Choose ref and reactive by purpose

ref is intuitive for primitive values or values that are clearly replaced as a whole. reactive can be more convenient when several related fields need to be handled together. Still, because destructuring can break reactivity, you need to understand the usage context before reaching for it.

Do not mix API types and UI types directly

If you use backend response models directly as screen component types, the frontend becomes tightly coupled to the response shape. It is more resilient to separate API DTOs, screen view models, and form input models when needed.

Responsibility comes before typing in composables

TypeScript is powerful, but that does not mean every piece of logic should become a generic composable. It is usually better to abstract only when a responsibility is truly repeated. The type system should support that responsibility safely, not become the reason the abstraction exists.

Wrap-up

The core of Vue 3 + TypeScript is not advanced type tricks, but stable contracts. If you think separately about props, emits, composables, and state models, types stop feeling like rules that slow development down and start acting like interfaces that help teams collaborate.

What Gets Hard in Production

  • Template inference can look safe while store, composable, and API boundaries still leak implicit any through the app.
  • Type safety gets weaker when props, emits, and async data shapes are inferred differently in every component.
  • A Vue codebase becomes hard to navigate when shared types and composables have no layering rules.

Architecture Decisions That Matter

  • Use strict TypeScript together with Volar-friendly conventions for props, emits, and composables.
  • Split transport, domain, and presentation models instead of letting ref and reactive hold raw API payloads everywhere.
  • Treat composables as public APIs and keep their return types stable and intentionally shaped.

Practical Example

A good baseline is to normalize server payloads before they enter reactive state:

type ProductResponse = {
  id: string
  product_name: string
  stock_count: number
}

type ProductViewModel = {
  id: string
  name: string
  isSoldOut: boolean
}

function toProductViewModel(product: ProductResponse): ProductViewModel {
  return {
    id: product.id,
    name: product.product_name,
    isSoldOut: product.stock_count <= 0,
  }
}

Anti-Patterns to Avoid

  • Keeping raw API objects in component state and mutating them across the template tree.
  • Using broad Record<string, unknown> types where the domain is actually known.
  • Creating composables whose return shape changes screen by screen.

Operational Checklist

  • Run type checking in CI independently from the build step.
  • Keep defineProps and defineEmits signatures explicit at shared component boundaries.
  • Review store and composable contracts whenever API schema changes.
  • Track editor and CI type latency once the project grows.

Final Judgment

Vue 3 with TypeScript works best when types reinforce composable boundaries and component contracts. Template inference alone is not enough for long-term architectural safety.

Continue Reading

Related posts

Next Path

Keep exploring this topic as a system