Vue 3 Prop Types with Typescript
🗓 October 20, 2021
Vue 3 + TS
Vue 3 adds really solid Typescript support. One place where it can get a little tricky, is typing the props we define for passing data into our components. Vue offers a "native js" way of doing this... but there are obviously limitations to this given the dynamic type system in js. Below are some patterns I've found for making prop types much more Typescript friendly. Enjoy!
PropType
import { PropType } from 'vue'
PropType
is a utility type provided by vue that allows you to effectively type a prop on your component by passing PropType your type of choice. Here's an example.
<template>
<div>
{{ label }}
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'CoolLabelComponent',
props: {
label: {
type: String as PropType<string>,
default: 'Label',
},
},
})
</script>
Use with Care
Notice in our prop definition for label
we force cast type: String as PropType<string>
. Make sure you're aware of what's going on here.... by using the as PropType<string>
we force Typescript to interpret whatever value is passed into our prop as a string
type, so you'll want to be confident that that prop is actually a string.
Handling Defaults
It's especially important to think about the as
syntax when providing a default value for your prop. In non-typescript vue code something like
props: {
label: {
type: String,
default: null,
},
},
is totally valid. We're saying that our label prop is a String
but by default it starts as null
. This is a pretty sane pattern, considering that many times prop data might get populated asynchronously or be optional.
To make sure we handle our null
default, we can use a union type. Then handle the potential null
value whenever we reference our prop. Here's what that looks like:
<template>
<div>
{{ lowerLabel }}
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'CoolLabelComponent',
props: {
label: {
type: String as PropType<string | null>,
default: null,
},
},
computed: {
lowerLabel () {
return this.label ? this.label.toLowerCase() : 'label is null 👀'
}
}
})
</script>