inb4: This is not another "setting up" a new project with Vue and TypeScript tutorial. Let's do some deep dive into more complex topics! typescript is awesome. Vue is awesome. No doubt, that a lot of people try to bundle them together. But, due to different reasons, it is hard to really type your Vue app. Let's find out what are the problems and what can be done to solve them (or at least minimize the impact). We have this wonderful template with Nuxt, Vue, Vuex, and jest fully typed. Just install it and everything will be covered for you. Go to the docs to learn more. And as I said I am not going to guide you through the basic setup for three reasons: The first broken expectation when you start to work with Vue and typescript and after you have already typed your class components is that <template> and <style> tags are still not typed. Let me show you an example: I have made two typos here: {{ usr }} instead of {{ user }} and $style.headr instead of $style.header. Will typescript save me from these errors? Nope, it won't. What can be done to fix it? Well, there are several hacks. One can use Vetur with vetur.experimental.templateInterpolationService option to type-check your templates. Yes, this is only an editor-based check and it cannot be used inside the CI yet. But, Vetur team is working hard to provide a CLI to allow this. Track the original issue in case you are interested.  The second option is two write snapshot tests with jest. It will catch a lot of template-based errors. And it is quite cheap in the maintenance. So, the combination of these two tools provides you a nice Developer Experience with fast feedback and a reliable way to catch errors inside the CI. Typing css-modules is also covered by several external tools: The main idea of these tools is to fetch css-modules and then create .d.ts declaration files out of them. Then your styles will be fully typed. It is still not implemented for Nuxt or Vue, but you can tract this issue for progress. However, I don't personally use any of these tools in my projects. They might be useful for projects with large code bases and a lot of styles, but I am fine with just snapshots. Styleguides with visual regression tests also help a lot. @storybook/addon-storyshots is a nice example of this technique. The next big thing is Vuex. It has some built-in by-design complexity for typing: The problem is that 'action_name' might no exist, take other arguments, or return a different type. That's not something you expect for a fully-typed app. What are the existing solutions? vuex-class is a set of decorators to allow easy access from your class-based components to the Vuex internals. But, it is not typed safe since it cannot interfere with the types of state, getters, mutations, and actions.  Of course, you can manually annotate types of properties.  But what are you going to do when the real type of your state, getters, mutations, or actions will change? You will have a hidden type mismatch. That's where vuex-simple helps us. It actually offers a completely different way to write your Vuex code and that's what makes it type safe. Let's have a look: Later this typed module can be registered inside your Vuex like so: Now we have a 100% native Vuex.Store instance and all the type information bundled with it. To use this typed store in the component we can write just one line of code: Now we have typed Vuex that can be safely used inside our project.
When we change something inside our store definition it is automatically reflected to the components that use this store. If something fails — we know it as soon as possible. There are also different libraries that do the same but have different API. Choose what suits you best. When we have Vuex correctly setup, we need to fill it with data.
Let's have a look at our action definition again: How can we know that it will really return a list of CommentType and not a single number or a bunch of AuthorType instances? We cannot control the server. And the server might actually break the contract. Or we can simply pass the wrong api instance, make a typo in the URL, or whatever. How can we be safe? We can use runtime typing! Let me introduce io-ts to you: What do we do here? And later we can use it our api calls: With the help of io-ts-promise, we can return a Promise in a failed state if the response from server does not match a ts.array(Comment) type. It really works like a validation. Moreover, return type annotation is in sync with the .decode method. And you cannot put random nonsense there:  With the combination of runtime and static checks, we can be sure that our requests won't fail because of the type mismatch.
But, to be 100% sure that everything works, I would recommend using contract-based testing: have a look at pact as an example. And monitor your app with Sentry. The next problem is that this.$router.push({ name: 'wrong!' }) does not work the way we want to. I would say that it would be ideal to be warned by the compiler that we are routing to the wrong direction and this route does not exist.
But, it is not possible. And not much can be done: there are a lot of dynamic routes, regex, fallbacks, permissions, etc that can eventually break. The only option is to test each this.$router call in your app. Speaking about tests I do not have any excuses not to mention @vue/test-utils that also has some problems with typing. When we will try to test our new shiny component with typedStore property, we will find out that we actually cannot do that according to the typescript:  Why does this happen? It happens because mount() call does not know anything about your component's type, because all components have a VueConstructor<Vue> type by default:  That's where all the problems come from. What can be done?
You can use vuetype to produce YouComponent.vue.d.ts typings that will tell your tests the exact type of the mounted component. You can also track this issue for the progress. But, I don't like this idea. These are tests, they can fail. No big deal.
That's why I stick to (wrapper.vm as any).whatever approach. This saves me quite a lot of time to write tests. But spoils Developer Experience a little bit. Make your own decision here: The average level of typescript support in Vue ecosystem increased over the last couple of years: But, it is production ready at the moment. These are just things to improve! Writing type-safe Vue code really improves your Developer Experience and allows you to focus on the important stuff while leaving the heavy-lifting to the compiler. What are your favourite hacks and tools to type Vue apps? Let's discuss it in the comment section. CTO at wemake.services