This will be the first in a series of articles talking about some of the things you’ll come across when creating Vue apps using Typescript. I am a rubber-meets-the-road developer who is developing Vue web applications for a living. Expect these articles to be focused on concrete things that might be of interest if you find yourself in a position where, for whatever reason, you find yourself using Typescript with your Vue. I’m not going to be proselytizing for the Church of Our Statically Typed Lady. At any rate: onto today’s topic!
Injected What?
When I am talking about injected properties I’m referring to how certain libraries will add a property to your main Vue component. A good example is how Vue Router and Vuex add a $route and $store property to the Vue instance which is accessible as this.$route and this.$store in your components.
These properties are handy to have and allow for quick access to all sorts of things without having to import, instantiate, invoke yet Another Thing into your component.
Property ‘$fizzbuzz’ does not exist on type ‘FizzBuzzView’
When you’re using Typescript and try to use one of these injected properties you’ll get an error like the header above this. What’s happening is that Vue supplies its own type definitions and Typescript dutifully takes a note of what properties, functions, etc exist on a Vue instance.
When libraries (or plugins, or whatever you have that adds a property to the Vue instance) tack on an extra property suddenly your Vue instance is ‘out of spec’ with the official Vue types for the instance. So Typescript does its job and lets you know that something ain’t right — that property doesn’t exist!
Of course, you know it exists. And if you force Typescript to chew and swallow and spit out some transpiled javascript (perhaps by casting the Vue instance as any) of course things work fine. That’s because the property really is on there and Javascript sure as heck knows about it. It’s just Typescript does not.
How to let Typescript Make Friends
Luckily there is a way to introduce shy, awkward Typescript to your cool, hip property injecting friends. And that way is to use Declaration Files. A Declaration File is basically a cheat-sheet that you give to Typescript to let it know that certain types exist and are totally cool and it should open up and let them in a little.
In essence, a declaration file tells Typescript about types that are defined OUTSIDE of Typescript. Another thing about declaration files is that you don’t have to import them. They are considered ambient which just means that Typescript will find these things itself and use them without you having to do anything.
So what does one of these look like? Let’s look at one!
import firebase from 'firebase' import Vue from 'vue' /* This file simply imports the needed types from firebase and forwards them */ declare module 'vue/types/vue' { interface Vue { $fireStore: firebase.firestore.Firestore $fireDb: firebase.database.Database $fireFunc: firebase.functions.Functions $fireStorage: firebase.storage.Storage $fireAuth: firebase.auth.Auth $fireMess: firebase.messaging.Messaging } }
There, not too scary is it? In this case I’m using a library (a nuxt module called nuxt-fire) that injects a bunch of properties onto the Vue instance that refer to various Firebasey things.
We import both firebase and Vue into our declaration file. That gives us access to the types we need. Now that we have our types, we declare a module. In particular we declare the exact same module that the official Vue types declare!
When Typescript finds multiple modules declared like this what it does is form a union — mashes them all together into one thing. So now Typescript knows all these $fireFoo properties exist on the Vue interface.
And more importantly for you the developer, your editor’s typescript integration now knows that too so you’ll get intellisense/code completion in addition to proper type checking for these injected props.
There’s nothing magic about these and you can create as many as you need. Here is another one for a neat thing called Vue ScrollTo that lets you easily animate scrolling to specific elements.
import VueScrollTo from 'vue-scrollto' import Vue from 'vue' declare module 'vue/types/vue' { interface Vue { $scrollTo: VueScrollTo } }
It’s the exact same as the firebase one except only injecting the single property. This is a pattern you can use again and again to provide typing information for anything that adds properties to the Vue instance.
Neat, but this just works for me without this?
Well lucky you! These days you might find the library or component you’re using already provides its own typings that do this. If things are already working fine for you then run with it!
But when they’re not, and when you really would like them to, remember your friend the declaration file, and do some introducing of your own.