A props declaration exists twice in a TypeScript component — once as a type and once as the runtime object Vue needs — and the type-only form generates the second from the first.
<script setup lang="ts">
interface Props {
order: Order
compact?: boolean
}
const props = withDefaults(defineProps<Props>(), {
compact: false,
})
const emit = defineEmits<{
(e: 'update', value: Order): void
}>()
</script>
The compiler generates the runtime declaration from the type, so there is one source of truth and the props are checked at compile time. The limitation is that the type must be resolvable in the same file — an interface imported from another module could not be used until later versions, which is the constraint that sends people back to the runtime form. withDefaults exists because a type has no defaults, and it reads awkwardly enough that most people meet it by error message.