TypeScript decorators for Vue.js class-based components with property binding, state management, and lifecycle capabilities
—
Re-exported components and utilities from vue-class-component and Vue core. These provide the foundational elements for class-based Vue component development and are essential for building components with decorators.
The core class decorator that transforms TypeScript classes into Vue components, enabling the class-based component syntax.
/**
* Class decorator that transforms TypeScript classes into Vue components
* @param options - Vue component options object (optional)
* @returns Decorated Vue component class
*/
const Component: ComponentDecorator;
interface ComponentDecorator {
<V extends VueClass<Vue>>(target: V): V;
<V extends VueClass<Vue>>(options: ComponentOptions<Vue>): (target: V) => V;
}
interface ComponentOptions<V extends Vue> {
name?: string;
components?: { [key: string]: Component | AsyncComponent };
directives?: { [key: string]: DirectiveFunction | DirectiveOptions };
filters?: { [key: string]: Function };
mixins?: ComponentOptions<Vue>[];
extends?: ComponentOptions<Vue>;
template?: string;
render?(createElement: CreateElement, hack: RenderContext<V>): VNode;
renderError?(createElement: CreateElement, err: Error): VNode;
staticRenderFns?: (() => VNode)[];
beforeCreate?(this: V): void;
created?(this: V): void;
beforeMount?(this: V): void;
mounted?(this: V): void;
beforeUpdate?(this: V): void;
updated?(this: V): void;
activated?(this: V): void;
deactivated?(this: V): void;
beforeDestroy?(this: V): void;
destroyed?(this: V): void;
errorCaptured?(this: V, err: Error, instance: Vue, info: string): boolean | void;
}Usage Examples:
import { Vue, Component } from "vue-property-decorator";
// Basic component
@Component
export default class BasicComponent extends Vue {
message = "Hello World";
}
// Component with options
@Component({
name: "MyCustomComponent",
components: {
ChildComponent: () => import("./ChildComponent.vue")
},
template: `
<div>
<h1>{{ title }}</h1>
<child-component />
</div>
`
})
export default class CustomComponent extends Vue {
title = "Custom Component";
}
// Component with lifecycle hooks
@Component
export default class LifecycleComponent extends Vue {
data = [];
created() {
console.log("Component created");
this.fetchData();
}
mounted() {
console.log("Component mounted");
}
beforeDestroy() {
console.log("Component will be destroyed");
this.cleanup();
}
private async fetchData() {
// Fetch data implementation
}
private cleanup() {
// Cleanup implementation
}
}The core Vue constructor class that provides all Vue instance methods and properties for class-based components.
/**
* Vue base class providing all Vue instance methods and properties
*/
const Vue: VueConstructor;
interface VueConstructor {
new <Data = object, Methods = object, Computed = object, Props = object>(
options?: ComponentOptions<Vue, Data, Methods, Computed, Props>
): CombinedVueInstance<Vue, Data, Methods, Computed, Props>;
extend<Data, Methods, Computed, Props>(
options?: ComponentOptions<Vue, Data, Methods, Computed, Props>
): ExtendedVue<Vue, Data, Methods, Computed, Props>;
component(id: string): VueConstructor;
component<Props>(id: string, definition: Component<any, any, any, Props>): ExtendedVue<Vue, {}, {}, {}, Props>;
use<T>(plugin: PluginFunction<T>, options?: T): VueConstructor;
use(plugin: PluginObject<any> | PluginFunction<any>, ...options: any[]): VueConstructor;
mixin(mixin: VueConstructor | ComponentOptions<Vue>): VueConstructor;
directive(id: string): DirectiveOptions;
directive(id: string, definition: DirectiveOptions | DirectiveFunction): VueConstructor;
filter(id: string): Function;
filter(id: string, definition: Function): VueConstructor;
compile(template: string): {
render(this: Component): VNode;
staticRenderFns: (() => VNode)[];
};
config: VueConfiguration;
version: string;
}Usage Examples:
import { Vue, Component } from "vue-property-decorator";
@Component
export default class MyComponent extends Vue {
// Vue instance properties and methods are available
message = "Hello";
// Access Vue instance methods
updateMessage() {
this.$nextTick(() => {
console.log("DOM updated");
});
}
// Access reactive data methods
setData() {
this.$set(this.someObject, "newKey", "newValue");
}
// Emit events
handleClick() {
this.$emit("custom-event", { data: this.message });
}
// Access lifecycle
mounted() {
console.log("Component element:", this.$el);
console.log("Parent component:", this.$parent);
console.log("Root component:", this.$root);
}
}Helper function for creating mixed component classes, enabling composition of multiple component behaviors.
/**
* Helper function for creating mixed component classes
* @param mixins - Array of Vue classes to mix
* @returns Mixed Vue class constructor
*/
function Mixins(...mixins: VueClass<Vue>[]): VueClass<Vue>;
type VueClass<V> = {
new(...args: any[]): V & Vue;
} & typeof Vue;Usage Examples:
import { Vue, Component, Mixins } from "vue-property-decorator";
// Define mixin classes
@Component
class TimestampMixin extends Vue {
created() {
console.log(`Component created at: ${new Date().toISOString()}`);
}
getTimestamp() {
return Date.now();
}
}
@Component
class ValidationMixin extends Vue {
errors: any = {};
validate(data: any): boolean {
// Validation logic
return Object.keys(this.errors).length === 0;
}
clearErrors() {
this.errors = {};
}
}
// Use mixins in component
@Component
export default class MixedComponent extends Mixins(TimestampMixin, ValidationMixin) {
formData = {};
// Now has access to methods from both mixins
handleSubmit() {
if (this.validate(this.formData)) {
console.log(`Form submitted at: ${this.getTimestamp()}`);
}
}
resetForm() {
this.formData = {};
this.clearErrors(); // From ValidationMixin
}
}
// Advanced mixin with generics
@Component
class DataMixin<T> extends Vue {
data: T[] = [];
loading = false;
async fetchData(url: string): Promise<T[]> {
this.loading = true;
try {
const response = await fetch(url);
this.data = await response.json();
return this.data;
} finally {
this.loading = false;
}
}
}
// Use generic mixin
interface User {
id: number;
name: string;
email: string;
}
@Component
export default class UserList extends Mixins(DataMixin) {
async mounted() {
await this.fetchData("/api/users");
}
get users(): User[] {
return this.data as User[];
}
}import { Vue, Component } from "vue-property-decorator";
// Base component with common functionality
@Component
class BaseFormComponent extends Vue {
loading = false;
errors: any = {};
protected async submitForm(data: any): Promise<void> {
this.loading = true;
this.errors = {};
try {
await this.performSubmit(data);
this.$emit("success", data);
} catch (error) {
this.errors = error.response?.data?.errors || { general: error.message };
this.$emit("error", error);
} finally {
this.loading = false;
}
}
protected async performSubmit(data: any): Promise<void> {
// Override in subclasses
throw new Error("performSubmit must be implemented");
}
}
// Specific form implementation
@Component
export default class UserRegistrationForm extends BaseFormComponent {
userData = {
name: "",
email: "",
password: ""
};
protected async performSubmit(data: any): Promise<void> {
const response = await fetch("/api/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error("Registration failed");
}
}
handleSubmit() {
this.submitForm(this.userData);
}
}import { Vue, Component } from "vue-property-decorator";
// Extend Vue with plugin types
declare module "vue/types/vue" {
interface Vue {
$http: {
get(url: string): Promise<any>;
post(url: string, data: any): Promise<any>;
};
$notify: {
success(message: string): void;
error(message: string): void;
};
}
}
@Component
export default class PluginAwareComponent extends Vue {
async loadData() {
try {
const data = await this.$http.get("/api/data");
this.$notify.success("Data loaded successfully");
return data;
} catch (error) {
this.$notify.error("Failed to load data");
throw error;
}
}
}interface ComponentOptions<V extends Vue, Data = DefaultData<V>, Methods = DefaultMethods<V>, Computed = DefaultComputed, Props = DefaultProps> {
data?: Data;
props?: Props;
propsData?: object;
computed?: Computed;
methods?: Methods;
watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any>>;
el?: Element | string;
template?: string;
render?(createElement: CreateElement, hack: RenderContext<V>): VNode;
renderError?(createElement: CreateElement, err: Error): VNode;
staticRenderFns?: (() => VNode)[];
beforeCreate?(this: V): void;
created?(this: V): void;
beforeMount?(this: V): void;
mounted?(this: V): void;
beforeUpdate?(this: V): void;
updated?(this: V): void;
activated?(this: V): void;
deactivated?(this: V): void;
beforeDestroy?(this: V): void;
destroyed?(this: V): void;
errorCaptured?(this: V, err: Error, instance: Vue, info: string): boolean | void;
directives?: { [key: string]: DirectiveFunction | DirectiveOptions };
components?: { [key: string]: Component | AsyncComponent };
transitions?: { [key: string]: object };
filters?: { [key: string]: Function };
provide?: object | (() => object);
inject?: InjectOptions;
model?: { prop?: string; event?: string };
parent?: Vue;
mixins?: (VueConstructor | ComponentOptions<Vue>)[];
name?: string;
extends?: VueConstructor | ComponentOptions<Vue>;
delimiters?: [string, string];
comments?: boolean;
inheritAttrs?: boolean;
}
type VueClass<V> = { new(...args: any[]): V & Vue } & typeof Vue;
type ComponentDecorator = <V extends VueClass<Vue>>(target: V) => V;Install with Tessl CLI
npx tessl i tessl/npm-vue-property-decorator