Vue Class Decorator
Vue Class Decorator (current version 7.6.3) is a library that provides additional decorators for defining Vue 2 components using a class-based, TypeScript-first syntax. It extends the capabilities of `vue-class-component` and `vue-property-decorator` by introducing decorators for functional components (`@FunctionalVue`), filters (`@Filter`), event handling (`@On`, `@Once`), and lifecycle hooks (`@Mounted`). This approach allows developers to define components, methods, and lifecycle hooks as class properties and methods, leveraging TypeScript's strong typing. The library is specifically tailored for Vue 2 projects and does not support Vue 3, where the Composition API is the recommended approach for component definition. Its release cadence has slowed considerably, with no recent updates for Vue 3 compatibility, positioning it primarily for legacy Vue 2 maintenance.
Common errors
-
TypeError: Class extends value undefined is not a constructor or null
cause This error typically occurs when `vue-class-component` is not properly installed, configured, or its imports are incorrect. `vue-class-decorator` depends on `vue-class-component` for the base `Vue` class extension.fixEnsure `vue-class-component` is installed (`npm install vue-class-component`) and correctly imported. Also, verify that `Vue` is imported from `vue-class-component` when defining your base class, or that `vue-class-decorator`'s re-exports are correctly handled. -
Support for the experimental syntax 'decorators' isn't currently enabled
cause Your TypeScript or Babel configuration does not have support for ECMAScript decorators enabled.fixIn `tsconfig.json`, ensure `"experimentalDecorators": true` and `"emitDecoratorMetadata": true` are set under `compilerOptions`. If using Babel, ensure `@babel/plugin-proposal-decorators` and `@babel/plugin-proposal-class-properties` are configured. -
Property 'myMethod' does not exist on type 'Vue'
cause This can happen if a decorated method's type inference is lost, or if you're trying to access a method that was removed by `@On`/`@Once` with `reserve: false`.fixCheck the decorator settings, especially `reserve` for `@On`/`@Once`. Ensure all necessary types are correctly inferred. If it's a lifecycle hook, make sure it's decorated correctly (e.g., `@Mounted()`).
Warnings
- breaking This library is fundamentally designed for Vue 2 and is not compatible with Vue 3. Migrating to Vue 3 requires refactoring components to use the Composition API or an alternative community-maintained class component solution like `vue-facing-decorator`.
- gotcha Using `@On` or `@Once` decorators with `reserve: false` will delete the decorated method from the component's `methods` object. This can lead to unexpected behavior if you later try to call the method directly (e.g., `this.myMethod()`) or through direct `$emit` listeners expecting it to exist.
- gotcha For TypeScript projects, the `tsconfig.json` must explicitly enable experimental decorators and emit decorator metadata. Without these settings, TypeScript will not correctly process the decorators, leading to compilation errors or runtime failures.
- deprecated The class component style of Vue development, while supported by this library for Vue 2, is largely superseded by the Composition API in Vue 3. New Vue projects or migrations should prioritize the Composition API for better long-term maintainability and official support.
Install
-
npm install vue-class-decorator -
yarn add vue-class-decorator -
pnpm add vue-class-decorator
Imports
- Component
import { Component } from 'vue-class-component'import { Component } from 'vue-class-decorator' - FunctionalVue
const { FunctionalVue } = require('vue-class-decorator')import { FunctionalVue } from 'vue-class-decorator' - Filter
import Filter from 'vue-class-decorator'
import { Filter } from 'vue-class-decorator' - On
import { On } from 'vue-class-decorator'
Quickstart
import Vue from 'vue';
import { Component, FunctionalVue, Filter, On, Mounted } from 'vue-class-decorator';
@Component
export class DateComponent extends Vue {
@Filter('formatDate')
private formatDate(value: string): string {
if (!value) return '';
const date = new Date(value);
return date.toLocaleDateString();
}
}
@Component
export default class MyFunctionalComponent extends FunctionalVue {
message: string = 'Hello from functional!';
}
@Component({
components: {
DateComponent
}
})
export class EventHandlerComponent extends Vue {
count: number = 0;
@On('increment')
handleIncrement(): void {
this.count++;
console.log('Incremented:', this.count);
}
@Mounted()
onMounted(): void {
console.log('EventHandlerComponent mounted!');
// Simulate emitting an event after 1 second
setTimeout(() => {
this.$emit('increment');
}, 1000);
}
}
new Vue({
el: '#app',
template: `
<div>
<date-component :value="new Date().toISOString()"></date-component>
<p>{{ '2023-10-26T10:00:00Z' | formatDate }}</p>
<event-handler-component></event-handler-component>
<p>Count in parent: {{ $children[2]?.count }}</p>
</div>
`
});