README.md

The only feature we want is TypeScript and Babel, so select those two.

We do not want the class-style component syntax

no need for babel in this simple demo

select "in dedicated files" for the config

Once that has finished installing, cd tsx_adder. We need one dependency to be able to use TSX. That is vue-tsx-support. Install in by running vue add tsx-support. We will also demonstrate Vuex with TypeScript, so add it with yarn add vuex.

The app we are building will look like this:

You can select a sign, and it will perform the calculation.

Structure

The application will have two components: App.tsx and Adder.tsx. The App.tsx will connect to the Vuex store and pass props to the Adder, which is the presentation component that will handle the layout and UI. As per the container/presenter pattern (also known as smart/dumb, container/component), In a large app, you would probably have an AdderContainer.tsx, but for simplicity I am just using App.tsx to interface with the store. Adder.tsx receives data from the store via props, and communicates with the parent by emitting events. This will let us demonstrate:

typesafe props, including complex types like Enums and Objects

typechecked events between the parent/child component

how to get type inference and type safety with Vuex State in components

Start off by converting App.vue to App.tsx. Update it to contain the following:

Now import it in App.tsx: import { Adder } from './components/Adder'. Lastly, head to main.ts and change import App from './App.vue to import { App } from './App'. Run yarn serve (or npm run serve). localhost:8080 should show the following:

Typesafe Props

The first thing we will demonstrate is typesafe props, including both primitives (like Number and Boolean) as well as complex types, like Enum. In Adder.tsx, add the following:

One caveat is you need to type true as true to get TypeScript to check the props at compile time. It is discussed breifly here. One you add that, if your editor supports TypeScript (for example VS Code), head back to App.tsx, and you should see an error, and <Adder > has a red line under it. Towards the end of the error message, it says Type '{}' is missing the following properties from type '{ left: number; right: number; }': left, right. Let's provide left and right in App.tsx:

render(): VNode {
return (
<Adderleft={5}
right={3}
/>
)
}

Try passing a string instead - TypeScript will warn us the prop type is incorrect.

Next, let's add a more complex type - an enum. Create a directory called types under src, and inside it a sign.ts file with the following:

enumSign {
'x'='x',
'/'='/',
'+'='+',
'-'='-'
}
export { Sign }

Next update Adder.tsx:

import { Sign } from'@/types/sign'// ...props: {
selectedSign: {
type: Stringas () =>Sign,
required: trueastrue
}
}
Anotherunforunatelyhack, whichshowssomeofthelimitsofVue's TS support is `String as () => Sign`. Since our `Sign` enum is just Strings, we do `String as () => ...`. If it was an enum of `Object` or `Array`, we would type `Array as () => MyComplexArrayType[]`. More information about this is found [here](https://frontendsociety.com/using-a-typescript-interfaces-and-types-as-a-prop-type-in-vuejs-508ab3f83480).Headbackto`App.tsx`, andyou'll see another error around `<Adder />`. Fix it by adding the following:```tsx// ...import { Sign } from '@/types/sign'// ... render(): VNode { return ( <Adder left={5} right={3} selectedSign={Sign['+']} /> ) }

Typesafe Events

Now let's see how to have typechecked events. We want the adder to emit a changeSign event when any of the four signs are clicked. This can be achieved using componentFactoryOf, documented here. Start by updating App.tsx:

Now the error is gone. Try changing the signature of changeSign(sign: Sign) to changeSign(sign: Number) - TS warns you the parameter has the incorrect type, very cool. Read more about componentFactoryOfhere.

Two last things to complete the Adder.tsx component. First, add the following interface at the top, and data function:

Then do import './adder.css' at the top of Adder.tsx. The page now looks like this:

Let's add Vuex and make the buttons work now.

Adding a Typesafe Vuex store

The next step for the app is adding a (somewhat) typsafe Vuex store. Make a store folder inside of src, then inside of store create index.ts and calculation.ts. Inside store/index.ts, add the following:

We need to type (this.$store.state as IState) to get typechecking on the store modules. There are other alternatives that will let you get type checking without casting this.$state to IState, but I've been using this pattern and found it pretty good so far.

Adding a Mutation

Let's add a mutation. The goal will be to save the selectedSign in the state, and update it with a mutation. Update calculation.ts:

We do not get any typechecking on the commit handler or payload. This is still a problem I'm exploring solutions to. There are a few solutions out there, but none of which feel clean enough, or require a level of abstraction I'm not happy with. I hope Vuex itself can evolve to provide a better TS experience out of the box in the future. I will propose my solution in a follow up article.

Let's finish the app off. Update App.tsx with the final code, which includes a computer property, result, to calculate the value based on the sign: