Top Related Projects
ES / TypeScript decorator for class-style Vue components.
TypeScript/ES7 Decorators to create Vuex modules declaratively
Quick Overview
Vue Property Decorator is a TypeScript decorator library for Vue.js. It provides a set of decorators that allow developers to use TypeScript classes and decorators with Vue components, making the code more concise and easier to read. This library is particularly useful for developers who prefer a class-based approach to Vue component development.
Pros
- Enhances TypeScript integration with Vue.js
- Simplifies component declaration and property management
- Improves code readability and maintainability
- Reduces boilerplate code in Vue components
Cons
- Requires TypeScript knowledge and setup
- May have a learning curve for developers new to decorators
- Adds an additional dependency to the project
- Some developers may prefer the traditional Vue.js object-based syntax
Code Examples
- Basic component with props and methods:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
@Prop({ default: 'Hello' }) readonly message!: string
greet(): void {
console.log(this.message)
}
}
- Using computed properties and watchers:
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
private count = 0
get doubleCount(): number {
return this.count * 2
}
@Watch('count')
onCountChange(newValue: number, oldValue: number): void {
console.log(`Count changed from ${oldValue} to ${newValue}`)
}
}
- Emitting events:
import { Vue, Component, Emit } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
@Emit()
addToCart(product: string): void {
// This method will emit an 'add-to-cart' event with the product as payload
}
}
Getting Started
- Install the package:
npm install --save-dev vue-property-decorator
- Enable decorators in your
tsconfig.json
:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
- Import and use decorators in your Vue components:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
@Prop() readonly name!: string
}
Competitor Comparisons
ES / TypeScript decorator for class-style Vue components.
Pros of vue-class-component
- Official Vue.js library, ensuring better long-term support and compatibility
- Lightweight and focused solely on class-based components
- Easier to understand and use for developers familiar with basic Vue.js concepts
Cons of vue-class-component
- Less feature-rich compared to vue-property-decorator
- Requires more boilerplate code for certain Vue.js features
- May need additional decorators or mixins for advanced use cases
Code Comparison
vue-class-component:
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class MyComponent extends Vue {
message: string = 'Hello World!'
}
vue-property-decorator:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
@Prop() readonly message!: string
}
vue-property-decorator builds upon vue-class-component, offering additional decorators for Vue.js features like @Prop
, @Watch
, and @Emit
. This results in more concise and expressive code, especially for complex components. However, it introduces an extra dependency and may have a steeper learning curve for beginners.
vue-class-component provides a solid foundation for class-based components in Vue.js, while vue-property-decorator extends its functionality with convenient decorators for various Vue.js features. The choice between the two depends on the project's complexity and the developer's preference for conciseness versus simplicity.
TypeScript/ES7 Decorators to create Vuex modules declaratively
Pros of vuex-module-decorators
- Specifically designed for Vuex, offering more Vuex-centric decorators
- Provides better TypeScript integration for Vuex modules
- Allows for more modular and organized Vuex store structure
Cons of vuex-module-decorators
- Steeper learning curve for developers new to decorators or Vuex
- May require additional setup and configuration compared to vue-property-decorator
- Limited to Vuex-specific use cases, less versatile for general Vue component decoration
Code Comparison
vue-property-decorator:
@Component
export default class MyComponent extends Vue {
@Prop() readonly message!: string
@Emit() onChange() {}
}
vuex-module-decorators:
@Module({ namespaced: true, name: 'myModule' })
class MyModule extends VuexModule {
@Mutation
setMessage(message: string) { /* ... */ }
@Action
async fetchData() { /* ... */ }
}
The vue-property-decorator focuses on decorating Vue component properties, while vuex-module-decorators specializes in Vuex store modules. The latter provides more specific decorators for Vuex concepts like mutations and actions, making it more suitable for complex state management scenarios. However, vue-property-decorator offers a broader range of decorators for general Vue component usage, making it more versatile for simpler applications or components that don't heavily rely on Vuex.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
[DEPRECATED] Vue Property Decorator
â ï¸ Notice
This library is no longer actively maintained. If you still want to use classes, check out the community-maintained project vue-facing-decorator
.
This library fully depends on vue-class-component, so please read its README before using this library.
License
MIT License
Install
npm i -S vue-property-decorator
Usage
There are several decorators and 1 function (Mixin):
@Prop
@PropSync
@Model
@ModelSync
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@VModel
@Component
(provided by vue-class-component)Mixins
(the helper function namedmixins
provided by vue-class-component)
See also
@Prop(options: (PropOptions | Constructor[] | Constructor) = {})
decorator
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Prop(Number) readonly propA: number | undefined
@Prop({ default: 'default value' }) readonly propB!: string
@Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
is equivalent to
export default {
props: {
propA: {
type: Number,
},
propB: {
default: 'default value',
},
propC: {
type: [String, Boolean],
},
},
}
If you'd like to set type
property of each prop value from its type definition, you can use reflect-metadata.
- Set
emitDecoratorMetadata
totrue
. - Import
reflect-metadata
before importingvue-property-decorator
(importingreflect-metadata
is needed just once.)
import 'reflect-metadata'
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
@Prop() age!: number
}
Each prop's default value need to be defined as same as the example code shown in above.
It's not supported to define each default
property like @Prop() prop = 'default value'
.
@PropSync(propName: string, options: (PropOptions | Constructor[] | Constructor) = {})
decorator
import { Vue, Component, PropSync } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@PropSync('name', { type: String }) syncedName!: string
}
is equivalent to
export default {
props: {
name: {
type: String,
},
},
computed: {
syncedName: {
get() {
return this.name
},
set(value) {
this.$emit('update:name', value)
},
},
},
}
@PropSync
works like @Prop
besides the fact that it takes the propName as an argument of the decorator, and also creates a computed getter and setter behind the scenes. This way you can interface with the property as if it was a regular data property whilst making it as easy as appending the .sync
modifier in the parent component.
@Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {})
decorator
import { Vue, Component, Model } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Model('change', { type: Boolean }) readonly checked!: boolean
}
is equivalent to
export default {
model: {
prop: 'checked',
event: 'change',
},
props: {
checked: {
type: Boolean,
},
},
}
@Model
property can also set type
property from its type definition via reflect-metadata
.
@ModelSync(propName: string, event?: string, options: (PropOptions | Constructor[] | Constructor) = {})
decorator
import { Vue, Component, ModelSync } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@ModelSync('checked', 'change', { type: Boolean })
readonly checkedValue!: boolean
}
is equivalent to
export default {
model: {
prop: 'checked',
event: 'change',
},
props: {
checked: {
type: Boolean,
},
},
computed: {
checkedValue: {
get() {
return this.checked
},
set(value) {
this.$emit('change', value)
},
},
},
}
@ModelSync
property can also set type
property from its type definition via reflect-metadata
.
@Watch(path: string, options: WatchOptions = {})
decorator
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged1(val: Person, oldVal: Person) {}
@Watch('person')
onPersonChanged2(val: Person, oldVal: Person) {}
@Watch('person')
@Watch('child')
onPersonAndChildChanged() {}
}
is equivalent to
export default {
watch: {
child: [
{
handler: 'onChildChanged',
immediate: false,
deep: false,
},
{
handler: 'onPersonAndChildChanged',
immediate: false,
deep: false,
},
],
person: [
{
handler: 'onPersonChanged1',
immediate: true,
deep: true,
},
{
handler: 'onPersonChanged2',
immediate: false,
deep: false,
},
{
handler: 'onPersonAndChildChanged',
immediate: false,
deep: false,
},
],
},
methods: {
onChildChanged(val, oldVal) {},
onPersonChanged1(val, oldVal) {},
onPersonChanged2(val, oldVal) {},
onPersonAndChildChanged() {},
},
}
@Provide(key?: string | symbol)
/ @Inject(options?: { from?: InjectKey, default?: any } | InjectKey)
decorator
import { Component, Inject, Provide, Vue } from 'vue-property-decorator'
const symbol = Symbol('baz')
@Component
export class MyComponent extends Vue {
@Inject() readonly foo!: string
@Inject('bar') readonly bar!: string
@Inject({ from: 'optional', default: 'default' }) readonly optional!: string
@Inject(symbol) readonly baz!: string
@Provide() foo = 'foo'
@Provide('bar') baz = 'bar'
}
is equivalent to
const symbol = Symbol('baz')
export const MyComponent = Vue.extend({
inject: {
foo: 'foo',
bar: 'bar',
optional: { from: 'optional', default: 'default' },
baz: symbol,
},
data() {
return {
foo: 'foo',
baz: 'bar',
}
},
provide() {
return {
foo: this.foo,
bar: this.baz,
}
},
})
@ProvideReactive(key?: string | symbol)
/ @InjectReactive(options?: { from?: InjectKey, default?: any } | InjectKey)
decorator
These decorators are reactive version of @Provide
and @Inject
. If a provided value is modified by parent component, then the child component can catch this modification.
const key = Symbol()
@Component
class ParentComponent extends Vue {
@ProvideReactive() one = 'value'
@ProvideReactive(key) two = 'value'
}
@Component
class ChildComponent extends Vue {
@InjectReactive() one!: string
@InjectReactive(key) two!: string
}
@Emit(event?: string)
decorator
The functions decorated by @Emit
$emit
their return value followed by their original arguments. If the return value is a promise, it is resolved before being emitted.
If the name of the event is not supplied via the event
argument, the function name is used instead. In that case, the camelCase name will be converted to kebab-case.
import { Vue, Component, Emit } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
count = 0
@Emit()
addToCount(n: number) {
this.count += n
}
@Emit('reset')
resetCount() {
this.count = 0
}
@Emit()
returnValue() {
return 10
}
@Emit()
onInputChange(e) {
return e.target.value
}
@Emit()
promise() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(20)
}, 0)
})
}
}
is equivalent to
export default {
data() {
return {
count: 0,
}
},
methods: {
addToCount(n) {
this.count += n
this.$emit('add-to-count', n)
},
resetCount() {
this.count = 0
this.$emit('reset')
},
returnValue() {
this.$emit('return-value', 10)
},
onInputChange(e) {
this.$emit('on-input-change', e.target.value, e)
},
promise() {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve(20)
}, 0)
})
promise.then((value) => {
this.$emit('promise', value)
})
},
},
}
@Ref(refKey?: string)
decorator
import { Vue, Component, Ref } from 'vue-property-decorator'
import AnotherComponent from '@/path/to/another-component.vue'
@Component
export default class YourComponent extends Vue {
@Ref() readonly anotherComponent!: AnotherComponent
@Ref('aButton') readonly button!: HTMLButtonElement
}
is equivalent to
export default {
computed() {
anotherComponent: {
cache: false,
get() {
return this.$refs.anotherComponent as AnotherComponent
}
},
button: {
cache: false,
get() {
return this.$refs.aButton as HTMLButtonElement
}
}
}
}
@VModel(propsArgs?: PropOptions)
decorator
import { Vue, Component, VModel } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@VModel({ type: String }) name!: string
}
is equivalent to
export default {
props: {
value: {
type: String,
},
},
computed: {
name: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
},
},
},
}
Top Related Projects
ES / TypeScript decorator for class-style Vue components.
TypeScript/ES7 Decorators to create Vuex modules declaratively
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot