Writing Single File Components (Vue Files) in Typescript: vue-class-component vs. Vue.extend
UPDATE:
This article was written in early 2018. Since is was written, Vue 2.6 was released, and the PR is merged! This article is out of date and I will write an update shortly.
If you come from Typescript, the first thing you’re looking for when picking up Vue is making sure your Vue files are type-safe.
While simply adding lang="ts"
to your script tag in your .vue
file and writing components like normal technically works, you’re missing out on basically 90% of the tooling Typescript offers.
This article will go over the two recommended ways of writing Vue components in Typescript, both of which are supported in the Vue documentation.
vue-class-component
vue-class-component is a ES / Typescript decorator that provides users with the abiliity to write class-style Vue components. It is usually used in conjunction with the vue-property-decorator.
Here is an example of a component written using vue-class-component:
The class will be mapped to a Vue component using the below blueprint:
- Data → any property on the class that is defined and instantiated
- Computed Properties → getters
- Methods → any property on the class that is a function
- Props → any property defined as a prop using the @prop() decorator or as an argument to the @component() decorator (example here)
Until recently, this has been the only way to get type-safety in your Vue components.
Vue.extend()
The latest release of Vue rewrote some parts of the Typescript architecture, and we have a new way to write Vue components in Typescript: Vue.extend.
I call this the classic method, because it’s literally the same exact thing as a standard Vue component, only it must be explicitly wrapped in Vue.extend.
Thanks to the latest changes and type-inference, the Typescript compiler can now automatically provide typings for your Vue components based on the object structure you provide as an argument in Vue.extend()
One important distinction between this and vue-class-components is that these are not classes, but basic objects.
Additionally, because this is the classic way of defining Vue components, all standard Vue tooling works out of the box (like Vetur).
But Which One Is Better?
While reading keep in mind: these are just style differences that achieve almost the same thing.
I personally prefer Vue.extend because I believe it’s easier to teach and reason about. Stylistically, it’s more like putting Typescript-in-Vue, as opposed to putting Vue-in-Typescript.
The additional layer of abstraction is not worth the convenience, especially with typed-props coming soon.
vue-class-component might make more sense if you have complex props that require custom typings. At the current version, it’s impossible to implicitly cast a prop to a class/interface using Vue.extend.
At the moment, both of these are included in the official documentation, so both will be supported.