Dependency Injection with TypeScript: good-injector Localization Support for my Blog

Vue.js-Plugins with TypeScript

Published on Friday, February 9, 2018 8:00:00 AM UTC in Programming

Plugins are the recommended way to augment the feature set of Vue.js with additional properties, methods, assets and more. Writing them in TypeScript with current versions of Vue.js is straight-forward, but the advice you can find on the web often refers to older versions and does not apply anymore. In fact, the contradictory recommendations you find there may be quite confusing: how do I refer to the Vue.js type in my plugin? Do I use VueConstructor? Some say simply use Vue. Or is it typeof Vue? Well, here is a general rule of thumb that will help and never lets you google for the required syntax again.

Ever since Vue.js shipped its own typings, to solve this problem you can simply look at them. There are basically two ways to define a plugin: either use a function-based approach or use a plugin-object (which really only is a wrapper for the plugin function). Both can be found at types/plugin.d.ts in the Vue.js package (following the code of version 2.5.13):

import { Vue as _Vue } from "./vue";

export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;

export interface PluginObject<T> {
  install: PluginFunction<T>;
  [key: string]: any;
}

There you go. That is exactly what you use as template for your own code. Let's write a plugin function!

import _Vue from "vue"; // <-- notice the changed import
import Axios from "axios";

// export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
export function AxiosPlugin(Vue: typeof _Vue, options?: any): void {
    Vue.prototype.$http = Axios;
}

That's everything needed for the implementation. For the sample, I simply attach Axios to Vue here. You can use the mixin or directive features to do more sophisticated augmentation if you want. And of course, you can make use of your own type-safe options if you need:

import _Vue from "vue";
import Axios from "axios";

// export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
export function AxiosPlugin<AxiosPlugOptions>(Vue: typeof _Vue, options?: AxiosPluginOptions): void {
    // do stuff with options
    Vue.prototype.$http = Axios;
}

export class AxiosPluginOptions {
    // add stuff
}

Configure and consume your plugin

The further steps required are similar to any other plugin. Make sure to configure it correctly on startup:

import Vue from "vue";
import { AxiosPlugin } from "./AxiosPlugin";

// pass in your custom options as second parameter if applicable
Vue.use(AxiosPlugin); 
new Vue({
    // ...
});

If your plugin extends the Vue prototype like my example above, you need to provide types so the compiler can actually pick that up correctly (otherwise you'll get compiler errors when you use your plugin in components):

// put this in your source folder somewhere
// with a .d.ts extension the TS compiler will pick it up automatically
import { AxiosStatic } from "axios";

declare module 'vue/types/vue' {
  interface Vue {
    $http: AxiosStatic;
  }
}

Using AxiosStatic here simply is a peculiarity of Axios, don't worry about it. You simply configure the type of your extended property or function here and are good to go in your components:

// in your components
this.$http.[...] // use all Axios features, with full intellisense support

Have fun!

Tags: TypeScript · Vue.js