Vue 3 comes with better Typescript support than its previous version. In fact, this version is built with Typescript from the ground up.
The compiler now provides macros, which are methods that we don’t need to import. However, they can only be used inside a setup script.
The ones you will use the most are defineProps
and defineEmits
. Let’s see how to type them with Typescript.
How to Type Vue 3 defineProps with Typescript
This macro, as the name suggests, allows us to define props accepted by the component.
Let’s imagine that our component will accept a list of users of the type User
. We can use the defineProps
macro with the PropType
type like so:
<script setup lang="ts">
import { type PropType } from 'vue'
import { User } from 'somewhere'
defineProps({
users: {
type: Array as PropType<User[]>,
required: true
}
})
</script>
This approach is called runtime declaration. Although it works fine, there is another way that doesn’t involve casting. With type declaration we pass the type directly to the macro:
<script setup lang="ts">
import { User } from 'somewhere'
defineProps<{
users: User[]
}>()
</script>
When we want to use the props in the setup script, we assign the return value of defineProps
to a variable
<script setup lang="ts">
import { User } from 'somewhere'
const props = defineProps<{
users: User[]
}>()
doSomethingWith(props.users)
</script>
You might be wondering, how can we provide default values with this approach. Don’t worry, withDefaults
macro got you covered:
<script setup lang="ts">
import { User } from 'somewhere'
const props = withDefaults(defineProps<{
users: User[]
}>(), {
users: () => []
})
doSomethingWith(props.user)
</script>
To give an Array prop type a default value provide a method that returns an array.
To make the users
prop optional, add the Typescript optional operator ?
to defineProps
:
<script setup lang="ts">
import { User } from 'somewhere'
const props = withDefaults(defineProps<{
users?: User[] // <----- here
}>(), {
users: () => []
})
doSomethingWith(props.user)
</script>
And of course, if we use the prop in the template we will get auto-completion:
How to Type Vue 3 defineEmits with Typescript
defineEmits
is a macro that allows us, also as the name suggests, to define the events that the component can emit to its parent. Similar to defineProps
, we pass types directly:
<script setup lang="ts">
defineEmits<{
(e: 'removeUser'): void
}>()
</script>
Furthermore, when the event contains data, we can also type that. To type the emitted value, add it as an extra param to the method type:
<script setup lang="ts">
defineEmits<{
(e: 'removeUser', user: User): void
}>()
</script>
To use it in the setup directly, assign the return value of defineEmits
to a variable and call with the event name and parameter.
<script setup lang="ts">
const emit = defineEmits<{
(e: 'removeUser', user: User): void
}>()
const onRemoveUserClick = (user: User) => {
emit('removeUser', user)
}
</script>
And if we listen to this event from a parent component we will get better typescript support now:
Conclusion
Vue 3 macros are a joy to work with, you don’t have to import them and they are Typescript friendly. this promotes better productivity and faster development.
Trending now