How to Use TypeScript with Vue.js: Your Go-to Guide
A tutorial on how to use TypeScript in a Vue.js application.
TypeScript has now become a crucial indicator sought out for in a hire, library, maintainer, or digital product. Read this article to learn how to use TypeScript in a Vue.js application.
Introduction
Vue.js developers generally have the option of developing applications in either plain ol’ JavaScript or its more strict type-safe superset, TypeScript. However, Vue 3.0 came with enhanced TypeScript support which provides a simpler, more efficient, and more robust type inference to make it possible to write reliable code.
Type checking in a Vue.js-powered application is the central concept behind this article. In this tutorial, we will go through a beginner’s guide for using TypeScript with Vue.js in the most common use cases. Let’s start our journey already.
Pre-requisites
What you’ll need for this tutorial:
- Knowledge of JavaScript.
- Node & NPM — To get started with the project, you’ll need to have Node v12.22.0 and NPM installed on your local machine. To confirm they’re installed, run the following commands in your terminal:
node -v && npm --v
The Node Package Manager comes installed with Node, and it allows us to install various application dependencies. If you don’t have them installed, you can follow the instructions on the official Node.js website.
3. Knowledge of setting up a Vue.js project.
Table of Contents
Here’s what we’ll cover today:
- What is TypeScript
- Project Setup
- Typing Ref
- Typing Reactive
- Typing Props
- Typing Computed
- Typing Emits
- Typing Template Refs
- Typing Provide and Inject
- Typing Events
- Conclusion
What is TypeScript?
According to Microsoft, TypeScript is a superset of JavaScript that compiles to clean JavaScript output that web browsers and any host can understand. TypeScript makes it possible for strict enforcement of variable types in order to code cleanly and make a codebase more scalable while building large-scale JavaScript applications.
Project Setup
Vue.js provides first-class TypeScript support, and vue-create
remains the best way to get started with creating a TypeScript-ready Vue.js project.
Let’s create the project for this tutorial and name it vue-typescript-sandbox, using the command below:
vue create vue-typescript-sandbox
PS: You can give your project a different name if you wish to.
While creating the project, you’d get asked a series of questions. For this tutorial, let’s go with the following configurations:
At this point, we have a Vue.js project powered by TypeScript.
If you take a look at the App.vue
file or any other Single File Component in the project, you’ll see it uses the amazing defineComponent()
method which makes it possible for TypeScript to properly infer types inside component options.
In the project folder, there are three unique files with the .ts extension:
- The
main.ts
file is the TypeScript version of amain.js
file in a plain JavaScript Vue.js project. - The
shims-vue.d.ts
file tells TypeScript how to understand Vue.js Single File Components. - The
tsconfig.json
file holds the configuration options for the TypeScript compiler.
At this point, the next thing is to return a setup()
object in the defineComponent()
method in App.vue
, which would make it possible to declare reactive states and have them accessible on the template for the various demonstrations, as shown below:
Typing Ref
To specify the type for a ref’s value in a Vue.js-TypesScript project, pass a generic argument when calling ref()
:
If the ref has no initial value, then the generic type argument will be a union type that includes undefined
, as shown below:
const age = ref<number | undefined>();
If you need to infer a type from an interface or object literal type in the same file, as shown below:
Typing Reactive
The recommended way to specify the type for reactive()
is by using interfaces, as shown below:
Typing Props
Suppose we are building a blog and we need to pass the age and name data we created in App.vue
into another Vue.js file with a different layout to represent a blog post. Using props will come to our rescue.
To give types to props in a Vue.js project, we need to use type casting on the prop’s type property with Vue.js’s PropType
generic, imported from vue
package:
Update App.vue
for this demonstration, so it becomes:
Then, copy/paste the following into a new file created in the components
folder called PropsFile.vue
, where we pass our props:
But when working with a more complex type, like an interface, we define the types we want in the interface, then cast the data property as that interface, and pass the interface as the PropType’s generic type argument.
Typing Computed
For computed()
, the type is inferred based on the value of the getter.
Suppose, the goal is to combine a first name and last name into a full name. In Vue.js, we can achieve this as demonstrated below:
In the above demonstration, if we try to replace string
with say number
type, we will get an error: No overload matches this call, Argument of type ‘() => string’ is not assignable to parameter of type ‘ComputedGetter<number>’. This is because, as said earlier, the appropriate type of the computed property has been inferred from the initial values.
In a case where the computed property has a setter, the setter does not need to have a return type because we’re setting a value that already has a type.
Typing Emits
Suppose there is a need to emit a close()
function from child to parent in a given project, the defineComponent()
is able to infer the allowed events for the emit
function exposed in the setup context:
Typing Template Refs
In order to type a template ref with the Composition API, we need to declare a ref in setup()
with the same name and make sure to account for the case where the ref has null
value. This is because template refs have an initial value of null
until the component is mounted.
We can account for this by setting the template ref to null
if the referenced element isn’t mounted yet and using optional chaining or type guards when accessing the value of the template ref.
The demonstration is shown with the following codes:
Here, we can see that the explicit generic type argument HTMLElement
which is usable for any template ref, is used. And once the component has been mounted, we access the click
event of the button. The verify()
function is used in the demonstration to verify that the illustration worked.
Typing Provide and Inject
To enable types for provided/injected values in a TypeScript-Vue.js project, we will use the InjectionKey
interface that we can import from the vue
package. The InjectionKey
interface is a generic type that extends Symbol
which can be used to sync the type of the injected value between the provider and consumer.
It’s ideal to export the Symbol(s) in a dedicated file so that they can be imported into multiple components as shown below:
Below is a demonstration of typing provide and inject for a particular product:
In the src
folder, create a file called keys.ts
:
Next, copy/paste the following into the provider component:
Then, copy/paste the following into the injector component:
One thing to note is that the inject
function always produces the resolved type in union with undefined
. This happens because there is the possibility that the injection has not yet been resolved. It is now up to you how you want to handle it.
To get rid of undefined
you’ll need to pass a fallback value to the inject
function. The amazing thing here is that the fallback value is also type-checked:
Typing Events
When working with native DOM events in the Vue.js Composition API, we can enable typing the argument we pass to the event handler as shown below:
An event
object (without type annotation) implicitly has any
type.
To find out the type of the event beforehand, you can first use a button for the event handler to log the event
object to get its type. You’ll see the type as the constructor for the given event object:
Conclusion
In this tutorial, we have learned how to apply TypeScript in Vue.js projects in various use cases that a Vue.js developer might encounter during development.
If you are new to TypeScript, hang on! (Haha! It can be fairly intimidating, as was the case for me 🙈.) The TypeScript journey that has just begun for you is a rewarding one and is worth the effort as it will open up a whole new world of development experience and benefits.
The best part is that TypeScript is a progressive tool; you can take it one step at a time, and before you know it, it becomes your new go-to language.
If you get stuck while using TypeScript within your Vue.js project, feel free to reach out to me or upload your project on Github for feedback from other developers! It’s a huge and very active Vue.js community out here!
Follow me for more posts on better ways to live and work. Thank you.
Resources
More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Check out our Community Discord and join our Talent Collective.