Vue typescript class and decorator based component system with support for ES class inheritance and Vue 3 composition API integration.
—
Decorators for reactive properties, props, template references, and data binding in Vue components.
Decorator for setup functions that return reactive data, integrating with Vue 3's Composition API.
/**
* Decorator for setup functions that return reactive data
* @param setupFunction - Function that returns reactive data or Promise of reactive data
* @returns Property decorator
*/
function Setup(setupFunction: OptionSetupFunction): PropertyDecorator;
type OptionSetupFunction = (
props: Readonly<any>,
ctx: SetupContext<any>
) => any | Promise<any>;
interface SetupConfig {
setupFunction: OptionSetupFunction;
}Usage Examples:
import { Component, Setup } from "vue-facing-decorator";
import { ref, computed, reactive } from "vue";
@Component
class SetupComponent {
// Simple reactive reference
@Setup(() => ref("initial value"))
message!: string;
// Reactive object
@Setup(() => reactive({ count: 0, items: [] }))
state!: { count: number; items: any[] };
// Computed property
@Setup(() => computed(() => `Count: ${this.state.count}`))
displayText!: string;
// Async setup
@Setup(async () => {
const data = await fetch('/api/data');
return ref(await data.json());
})
asyncData!: any;
// Setup with context
@Setup((props, { emit, slots, attrs }) => {
const handleClick = () => emit('clicked');
return ref({ handleClick });
})
handlers!: { handleClick: () => void };
}Decorator for template references ($refs) with optional custom key names.
/**
* Decorator for template references
* @param key - Optional custom ref key name, defaults to property name
* @returns Property decorator
*/
function Ref(key?: string): PropertyDecorator;
type RefConfig = null | string;Usage Examples:
import { Component, Ref } from "vue-facing-decorator";
@Component({
template: `
<div>
<input ref="inputElement" />
<button ref="submitBtn">Submit</button>
<div ref="customKey">Custom</div>
</div>
`
})
class RefComponent {
// Basic ref - uses property name as ref key
@Ref()
inputElement!: HTMLInputElement;
// Basic ref with different property name
@Ref()
submitBtn!: HTMLButtonElement;
// Custom ref key
@Ref("customKey")
myDiv!: HTMLDivElement;
mounted() {
// Access refs after component is mounted
this.inputElement.focus();
this.submitBtn.addEventListener('click', this.handleSubmit);
this.myDiv.style.color = 'blue';
}
handleSubmit() {
console.log('Input value:', this.inputElement.value);
}
}Decorator for component props with comprehensive validation and configuration options.
/**
* Decorator for component props with validation
* @param config - Optional prop configuration
* @returns Property decorator
*/
function Prop(config?: PropsConfig): PropertyDecorator;
interface PropsConfig {
type?: any;
required?: boolean;
default?: any;
validator?(value: any): boolean;
}Usage Examples:
import { Component, Prop } from "vue-facing-decorator";
@Component
class PropComponent {
// Basic prop
@Prop()
message!: string;
// Required prop with type
@Prop({ type: String, required: true })
title!: string;
// Prop with default value
@Prop({ type: Number, default: 0 })
count!: number;
// Prop with validator
@Prop({
type: String,
validator: (value: string) => ['small', 'medium', 'large'].includes(value)
})
size!: 'small' | 'medium' | 'large';
// Complex prop types
@Prop({ type: Array, default: () => [] })
items!: any[];
@Prop({ type: Object, default: () => ({}) })
config!: Record<string, any>;
// Custom prop type
@Prop({
type: [String, Number],
validator: (value) => {
return (typeof value === 'string' && value.length > 0) ||
(typeof value === 'number' && value > 0);
}
})
id!: string | number;
}Decorator for v-model binding with two-way data flow support.
/**
* Decorator for v-model binding
* @param config - Optional v-model configuration extending PropsConfig
* @returns Property decorator
*/
function VModel(config?: VModelConfig): PropertyDecorator;
// Alias for VModel
const Model: typeof VModel;
interface VModelConfig extends PropsConfig {
name?: string;
}Usage Examples:
import { Component, VModel } from "vue-facing-decorator";
@Component({
template: `
<div>
<input v-model="value" />
<input v-model="customModel" />
</div>
`
})
class VModelComponent {
// Basic v-model (uses 'modelValue' prop and 'update:modelValue' event)
@VModel()
value!: string;
// Custom v-model name
@VModel({ name: "customValue" })
customModel!: string;
// V-model with validation
@VModel({
type: String,
validator: (value: string) => value.length <= 100
})
limitedText!: string;
// V-model with default
@VModel({
type: Number,
default: 0,
name: "count"
})
counter!: number;
}
// Usage in parent component:
// <VModelComponent v-model="parentValue" v-model:customValue="customValue" />Decorator to preserve original class properties without transformation.
/**
* Decorator to preserve original class properties without Vue transformation
* @returns Property decorator
*/
function Vanilla(): PropertyDecorator;Usage Examples:
import { Component, Vanilla, Setup } from "vue-facing-decorator";
import { ref } from "vue";
@Component
class VanillaComponent {
// This will be transformed to reactive data
@Setup(() => ref("reactive"))
reactiveProperty!: string;
// This will be preserved as-is, not transformed
@Vanilla()
staticProperty = "not reactive";
// Vanilla method - preserved as class method
@Vanilla()
utilityMethod() {
return "utility function";
}
// Regular method - becomes Vue component method
componentMethod() {
return this.reactiveProperty + " from component";
}
mounted() {
console.log(this.staticProperty); // "not reactive"
console.log(this.utilityMethod()); // "utility function"
console.log(this.componentMethod()); // "reactive from component"
}
}The property decorators follow specific transformation rules:
$refsComplete Example:
import { Component, Setup, Ref, Prop, VModel, Vanilla } from "vue-facing-decorator";
import { ref, computed } from "vue";
@Component({
template: `
<div>
<h1>{{ title }}</h1>
<input ref="textInput" v-model="inputValue" />
<p>{{ computedMessage }}</p>
<button @click="logStatic">Log Static</button>
</div>
`
})
class CompletePropertyExample {
// Prop from parent
@Prop({ type: String, required: true })
title!: string;
// Two-way binding
@VModel()
inputValue!: string;
// Reactive computed property
@Setup(() => computed(() => `You typed: ${this.inputValue}`))
computedMessage!: string;
// Template ref
@Ref()
textInput!: HTMLInputElement;
// Static property (not reactive)
@Vanilla()
staticValue = "I don't change reactively";
// Method
logStatic() {
console.log(this.staticValue);
this.textInput.focus();
}
}Install with Tessl CLI
npx tessl i tessl/npm-vue-facing-decorator