0
# Property Decorators
1
2
Decorators for reactive properties, props, template references, and data binding in Vue components.
3
4
## Capabilities
5
6
### Setup Decorator
7
8
Decorator for setup functions that return reactive data, integrating with Vue 3's Composition API.
9
10
```typescript { .api }
11
/**
12
* Decorator for setup functions that return reactive data
13
* @param setupFunction - Function that returns reactive data or Promise of reactive data
14
* @returns Property decorator
15
*/
16
function Setup(setupFunction: OptionSetupFunction): PropertyDecorator;
17
18
type OptionSetupFunction = (
19
props: Readonly<any>,
20
ctx: SetupContext<any>
21
) => any | Promise<any>;
22
23
interface SetupConfig {
24
setupFunction: OptionSetupFunction;
25
}
26
```
27
28
**Usage Examples:**
29
30
```typescript
31
import { Component, Setup } from "vue-facing-decorator";
32
import { ref, computed, reactive } from "vue";
33
34
@Component
35
class SetupComponent {
36
// Simple reactive reference
37
@Setup(() => ref("initial value"))
38
message!: string;
39
40
// Reactive object
41
@Setup(() => reactive({ count: 0, items: [] }))
42
state!: { count: number; items: any[] };
43
44
// Computed property
45
@Setup(() => computed(() => `Count: ${this.state.count}`))
46
displayText!: string;
47
48
// Async setup
49
@Setup(async () => {
50
const data = await fetch('/api/data');
51
return ref(await data.json());
52
})
53
asyncData!: any;
54
55
// Setup with context
56
@Setup((props, { emit, slots, attrs }) => {
57
const handleClick = () => emit('clicked');
58
return ref({ handleClick });
59
})
60
handlers!: { handleClick: () => void };
61
}
62
```
63
64
### Ref Decorator
65
66
Decorator for template references (`$refs`) with optional custom key names.
67
68
```typescript { .api }
69
/**
70
* Decorator for template references
71
* @param key - Optional custom ref key name, defaults to property name
72
* @returns Property decorator
73
*/
74
function Ref(key?: string): PropertyDecorator;
75
76
type RefConfig = null | string;
77
```
78
79
**Usage Examples:**
80
81
```typescript
82
import { Component, Ref } from "vue-facing-decorator";
83
84
@Component({
85
template: `
86
<div>
87
<input ref="inputElement" />
88
<button ref="submitBtn">Submit</button>
89
<div ref="customKey">Custom</div>
90
</div>
91
`
92
})
93
class RefComponent {
94
// Basic ref - uses property name as ref key
95
@Ref()
96
inputElement!: HTMLInputElement;
97
98
// Basic ref with different property name
99
@Ref()
100
submitBtn!: HTMLButtonElement;
101
102
// Custom ref key
103
@Ref("customKey")
104
myDiv!: HTMLDivElement;
105
106
mounted() {
107
// Access refs after component is mounted
108
this.inputElement.focus();
109
this.submitBtn.addEventListener('click', this.handleSubmit);
110
this.myDiv.style.color = 'blue';
111
}
112
113
handleSubmit() {
114
console.log('Input value:', this.inputElement.value);
115
}
116
}
117
```
118
119
### Prop Decorator
120
121
Decorator for component props with comprehensive validation and configuration options.
122
123
```typescript { .api }
124
/**
125
* Decorator for component props with validation
126
* @param config - Optional prop configuration
127
* @returns Property decorator
128
*/
129
function Prop(config?: PropsConfig): PropertyDecorator;
130
131
interface PropsConfig {
132
type?: any;
133
required?: boolean;
134
default?: any;
135
validator?(value: any): boolean;
136
}
137
```
138
139
**Usage Examples:**
140
141
```typescript
142
import { Component, Prop } from "vue-facing-decorator";
143
144
@Component
145
class PropComponent {
146
// Basic prop
147
@Prop()
148
message!: string;
149
150
// Required prop with type
151
@Prop({ type: String, required: true })
152
title!: string;
153
154
// Prop with default value
155
@Prop({ type: Number, default: 0 })
156
count!: number;
157
158
// Prop with validator
159
@Prop({
160
type: String,
161
validator: (value: string) => ['small', 'medium', 'large'].includes(value)
162
})
163
size!: 'small' | 'medium' | 'large';
164
165
// Complex prop types
166
@Prop({ type: Array, default: () => [] })
167
items!: any[];
168
169
@Prop({ type: Object, default: () => ({}) })
170
config!: Record<string, any>;
171
172
// Custom prop type
173
@Prop({
174
type: [String, Number],
175
validator: (value) => {
176
return (typeof value === 'string' && value.length > 0) ||
177
(typeof value === 'number' && value > 0);
178
}
179
})
180
id!: string | number;
181
}
182
```
183
184
### VModel Decorator
185
186
Decorator for v-model binding with two-way data flow support.
187
188
```typescript { .api }
189
/**
190
* Decorator for v-model binding
191
* @param config - Optional v-model configuration extending PropsConfig
192
* @returns Property decorator
193
*/
194
function VModel(config?: VModelConfig): PropertyDecorator;
195
196
// Alias for VModel
197
const Model: typeof VModel;
198
199
interface VModelConfig extends PropsConfig {
200
name?: string;
201
}
202
```
203
204
**Usage Examples:**
205
206
```typescript
207
import { Component, VModel } from "vue-facing-decorator";
208
209
@Component({
210
template: `
211
<div>
212
<input v-model="value" />
213
<input v-model="customModel" />
214
</div>
215
`
216
})
217
class VModelComponent {
218
// Basic v-model (uses 'modelValue' prop and 'update:modelValue' event)
219
@VModel()
220
value!: string;
221
222
// Custom v-model name
223
@VModel({ name: "customValue" })
224
customModel!: string;
225
226
// V-model with validation
227
@VModel({
228
type: String,
229
validator: (value: string) => value.length <= 100
230
})
231
limitedText!: string;
232
233
// V-model with default
234
@VModel({
235
type: Number,
236
default: 0,
237
name: "count"
238
})
239
counter!: number;
240
}
241
242
// Usage in parent component:
243
// <VModelComponent v-model="parentValue" v-model:customValue="customValue" />
244
```
245
246
### Vanilla Decorator
247
248
Decorator to preserve original class properties without transformation.
249
250
```typescript { .api }
251
/**
252
* Decorator to preserve original class properties without Vue transformation
253
* @returns Property decorator
254
*/
255
function Vanilla(): PropertyDecorator;
256
```
257
258
**Usage Examples:**
259
260
```typescript
261
import { Component, Vanilla, Setup } from "vue-facing-decorator";
262
import { ref } from "vue";
263
264
@Component
265
class VanillaComponent {
266
// This will be transformed to reactive data
267
@Setup(() => ref("reactive"))
268
reactiveProperty!: string;
269
270
// This will be preserved as-is, not transformed
271
@Vanilla()
272
staticProperty = "not reactive";
273
274
// Vanilla method - preserved as class method
275
@Vanilla()
276
utilityMethod() {
277
return "utility function";
278
}
279
280
// Regular method - becomes Vue component method
281
componentMethod() {
282
return this.reactiveProperty + " from component";
283
}
284
285
mounted() {
286
console.log(this.staticProperty); // "not reactive"
287
console.log(this.utilityMethod()); // "utility function"
288
console.log(this.componentMethod()); // "reactive from component"
289
}
290
}
291
```
292
293
## Property Transformation Rules
294
295
The property decorators follow specific transformation rules:
296
297
1. **Setup**: Properties become part of the component's setup function return
298
2. **Ref**: Properties become accessors for template refs via `$refs`
299
3. **Prop**: Properties become Vue component props with validation
300
4. **VModel**: Properties become computed properties with getter/setter for two-way binding
301
5. **Vanilla**: Properties are preserved exactly as defined in the class
302
303
**Complete Example:**
304
305
```typescript
306
import { Component, Setup, Ref, Prop, VModel, Vanilla } from "vue-facing-decorator";
307
import { ref, computed } from "vue";
308
309
@Component({
310
template: `
311
<div>
312
<h1>{{ title }}</h1>
313
<input ref="textInput" v-model="inputValue" />
314
<p>{{ computedMessage }}</p>
315
<button @click="logStatic">Log Static</button>
316
</div>
317
`
318
})
319
class CompletePropertyExample {
320
// Prop from parent
321
@Prop({ type: String, required: true })
322
title!: string;
323
324
// Two-way binding
325
@VModel()
326
inputValue!: string;
327
328
// Reactive computed property
329
@Setup(() => computed(() => `You typed: ${this.inputValue}`))
330
computedMessage!: string;
331
332
// Template ref
333
@Ref()
334
textInput!: HTMLInputElement;
335
336
// Static property (not reactive)
337
@Vanilla()
338
staticValue = "I don't change reactively";
339
340
// Method
341
logStatic() {
342
console.log(this.staticValue);
343
this.textInput.focus();
344
}
345
}
346
```