TypeScript props in Vue can be declared two ways: runtime declaration with type annotations, or pure type-based declaration.
Type-Based Declaration (Recommended)
Pass types directly to defineProps:
vue<script setup lang="ts"> // Simple props const props = defineProps<{ title: string count: number disabled?: boolean // Optional }>() </script>
With Interface
vue<script setup lang="ts"> interface Props { title: string count: number disabled?: boolean items: string[] user: { id: number name: string } } const props = defineProps<Props>() </script>
With Type Alias
vue<script setup lang="ts"> type Status = 'pending' | 'active' | 'completed' type Props = { id: number status: Status tags: string[] } const props = defineProps<Props>() </script>
Default Values with withDefaults
vue<script setup lang="ts"> interface Props { msg?: string count?: number items?: string[] user?: { name: string } } const props = withDefaults(defineProps<Props>(), { msg: 'Hello', count: 0, // Use factory functions for non-primitive defaults items: () => [], user: () => ({ name: 'Guest' }) }) </script>
Reactive Props Destructure (Vue 3.5+)
vue<script setup lang="ts"> interface Props { count: number msg?: string } // Destructure with defaults - stays reactive! const { count, msg = 'Hello' } = defineProps<Props>() // Can use directly console.log(count, msg) </script>
Complex Prop Types
vue<script setup lang="ts"> import type { Component } from 'vue' // Union types type Size = 'small' | 'medium' | 'large' type Variant = 'primary' | 'secondary' | 'danger' // Generic types type SelectOption<T> = { label: string value: T disabled?: boolean } interface Props { // Literal types size: Size variant: Variant // Array of objects options: SelectOption<string>[] // Function props formatter: (value: number) => string // Vue component as prop icon?: Component // Any HTML element element?: keyof HTMLElementTagNameMap } const props = defineProps<Props>() </script>
Runtime Declaration (Alternative)
Use when you need runtime validation:
vue<script setup lang="ts"> import type { PropType } from 'vue' interface User { id: number name: string } const props = defineProps({ // Simple types title: String, count: Number, // Required with type id: { type: Number, required: true }, // Complex type with PropType user: { type: Object as PropType<User>, required: true }, // Array of complex type items: { type: Array as PropType<User[]>, default: () => [] }, // Function prop callback: { type: Function as PropType<(id: number) => void>, required: false }, // Union type with validator status: { type: String as PropType<'active' | 'inactive'>, default: 'active', validator: (value: string) => ['active', 'inactive'].includes(value) } }) </script>
Importing Types for Props
typescript// types/user.ts export interface User { id: number name: string email: string } export type UserRole = 'admin' | 'user' | 'guest'
vue<script setup lang="ts"> import type { User, UserRole } from '@/types/user' const props = defineProps<{ user: User role: UserRole }>() </script>