TypeScript in Vue

defineProps/defineEmits Get Generic

TypeScript in Vue

Generic forms of the script-setup macros give full TS inference for props and emits — no runtime declarations, full type-checking in templates with Volar.

4 min read Level 2/5 #vue#typescript#types
What you'll learn
  • Use defineProps with a type literal
  • Use defineEmits with named events and tuples
  • Type refs explicitly where inference fails

Vue’s <script setup> macros each have a generic form that lets you describe shapes purely in TypeScript — no runtime objects, no manual PropType casts.

Typed Props

Pass an interface or inline type literal to defineProps.

<script setup lang="ts">
interface Props {
  name: string
  age?: number
  tags?: string[]
}

const props = defineProps<Props>()
</script>

Defaults for optional props need withDefaults:

<script setup lang="ts">
const props = withDefaults(defineProps<Props>(), {
  age: 0,
  tags: () => [],
})
</script>

Typed Emits

Tuple syntax — each event maps to the args it carries.

const emit = defineEmits<{
  save: [user: User]
  cancel: []
  'page-change': [page: number]
}>()

emit('save', { id: 1, name: 'Ada' })

Typed Refs

ref() infers, but for “starts null, gets set later” you’ll want an explicit generic.

import { ref } from 'vue'

const name = ref<string>('')          // string
const user = ref<User | null>(null)   // tagged union
const list = ref<User[]>([])          // generic array

Template Refs

Component refs need the typeof the component for full IntelliSense.

<script setup lang="ts">
import { useTemplateRef } from 'vue'
import MyInput from './MyInput.vue'

const inputRef = useTemplateRef<InstanceType<typeof MyInput>>('input')
</script>

Volar

Install the Vue (Official) extension for VS Code (a.k.a. Volar). It type-checks templates — wrong prop names and missing emits show up as errors in your editor.

Internationalization With vue-i18n →