Using a Typescript interface or type as a prop type in VueJS
As covered in our previous article about Writing Single File Components in Typescript, there’s two ways of creating a “component” in Vue and Typescript: using vue-class-component or Vue.extend.
If you’re using Vue in vanilla Javascript, a prop can only be an “Object,” and you’ll need to manually validate the object has specific keys on it at runtime in order to confirm it is correct.
With Typescript, you actually can take full advantage of Typescript’s static typing with a “Object” Vue prop. This provides you full auto complete on object properties and static checking of a property’s existence at compile time.
How do you do it?
Just cast the Object to a function that returns the interface you’d like it to implement.
Why Does This Work?
When you pass an Object
as a prop type into Vue component, you’re actually passing an Object constructor.
In order to validate this prop at runtime, Vue runs validation code similar to to what is listed above in order to check that it is in fact an instanceof
the “type” provided.
Typescript interfaces do not exist at runtime, so this:
will look like this once it’s compiled to Javascript, hence the squiggly red line:
Casting the Object
to your interface also will not work, as your interface does not implement the methods that the native Object
constructor does
The reason this works:
is because Vue’s Typescript typings internally treat any function passed as a ‘type’ as a function that returns an instance of the interface.
It’s a little confusing, but to be honest, most things in life are.
Is There A Better Way?
There is an open pull request to expose a PropTypes
interface that will allow you to cast the Object
constructor to a complex interface, like this:
props: {
testProp: Object as PropTypes<{ test: boolean }>
}
But for now, the only way to type complex prop types without adopting vue-class-component is to cast the Object as a function that returns the interface, like this:
props: {
testProp: Object as () => { test: boolean }
}