Vue Decorators for Vue 3 (Wrapper)
`vue-decorator` (v1.1.3, last updated March 2022) aims to provide custom decorators compatible with Vue 3 by acting as a wrapper for `vue-class-component` and `vue-property-decorator`. However, the core dependencies it wraps are largely unmaintained or officially archived for Vue 3 compatibility. `vue-property-decorator` explicitly states it does not support Vue 3, and `vue-class-component` has been superseded by `vue-facing-decorator` for modern Vue 3 class component usage. Due to the unmaintained status of both `vue-decorator` itself and its underlying dependencies for Vue 3, it is not recommended for new projects. Developers should consider `vue-facing-decorator` or directly use Vue 3's Composition API, which is the idiomatic approach for current Vue development. This package has a very slow release cadence, with its last update over two years ago.
Common errors
-
Decorators are not enabled in your TypeScript configuration. Consider setting the 'experimentalDecorators' compiler option in your 'tsconfig.json'.
cause TypeScript compiler is not configured to process decorators.fixAdd `"experimentalDecorators": true, "emitDecoratorMetadata": true` to your `compilerOptions` in `tsconfig.json`. -
TypeError: Cannot read properties of undefined (reading 'registerHooks')
cause Likely due to incompatibility between `vue-decorator`'s underlying dependencies and the Vue 3 runtime, or incorrect setup of `vue-class-component` for Vue 3.fixEnsure `vue-class-component` is correctly installed and configured for Vue 3, or, more reliably, migrate to `vue-facing-decorator` or the Composition API. -
Component is not a function
cause Incorrect import of `Component` (e.g., attempting a default import) or a problem with the module resolution.fixUse a named import: `import { Component } from 'vue-decorator';`
Warnings
- breaking The underlying libraries, `vue-class-component` and `vue-property-decorator`, which `vue-decorator` wraps, are largely unsupported or archived for Vue 3 compatibility. `vue-property-decorator` officially does not support Vue 3. Using this package may lead to runtime errors or unexpected behavior with modern Vue 3 versions and tooling.
- gotcha Using TypeScript decorators requires specific compiler options (`experimentalDecorators` and `emitDecoratorMetadata`) in `tsconfig.json`. Without these, TypeScript will not process the decorators correctly, leading to compilation or runtime errors.
- deprecated Class-style components, while supported by community packages like `vue-facing-decorator`, are not the officially recommended approach for Vue 3. The Vue core team recommends using Single-File Components with the Composition API and `<script setup>` for new development due to better type inference, reusability, and long-term support.
- breaking `vue-decorator` itself has not been updated since March 2022. This lack of active maintenance means it may not be compatible with newer versions of Vue 3, TypeScript, or related tooling, and it will not receive bug fixes or security patches.
Install
-
npm install vue-decorator -
yarn add vue-decorator -
pnpm add vue-decorator
Imports
- Component
import Component from 'vue-decorator';
import { Component } from 'vue-decorator'; - Prop
import { Prop } from 'vue-property-decorator';import { Prop } from 'vue-decorator'; - Watch
import { Watch } from 'vue-decorator'; - Emit
import { Emit } from 'vue-decorator';
Quickstart
import { Component, Prop, Watch, Emit } from 'vue-decorator';
import { Vue } from 'vue-class-component'; // Vue 3 compatibility requires Vue from vue-class-component
@Component({
template: `
<div>
<p>Hello, {{ userName }}!</p>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<input type="text" :value="message" @input="updateMessage(($event.target as HTMLInputElement).value)" />
<p>Message: {{ message }}</p>
</div>
`
})
export default class MyComponent extends Vue {
@Prop({ default: 'Guest' })
readonly userName!: string;
count: number = 0;
message: string = 'Initial message';
@Watch('count')
onCountChanged(newValue: number, oldValue: number) {
console.log(`Count changed from ${oldValue} to ${newValue}`);
}
@Emit('message-updated')
updateMessage(value: string) {
this.message = value;
return value;
}
increment() {
this.count++;
}
mounted() {
console.log('Component mounted with user:', this.userName);
}
}