TypeScript – Data Model Interfaces

In this chapter, we will keep building and improving our Vue project by starting to leverage TypeScript interfaces for strong-type checking at development time. One of the disadvantage or pure JavaScript is that is loosely typed, and this might cause issues at run-time as there are no checks on the type and or the expected properties of a value or object passed around through our code. TypeScript main advantage is the ability to enforce strong-type checking at development time through the use of interfaces, types, classes, and more.

Models Directory

Start by creating a new sub-directory under src called models. Since the focus of this book is on building a foundation for large applications, we’ll keep structuring our files and directories in a consistent way, following our own convention. You and your team are free to decide what your standards will be, but it’s important to have both files/directory naming conventions and structuring in place as soon as you start building a large application. This will save you a lot of confusion and headaches later as the application grows exponentially and the number of source files and directories grows with it.

Interface IItem

Within the src/models directory, create a sub-directory called items. Within this directory we’ll add a new TypeScript file called IItem.ts. Note: we’ll be following a naming convention for TypeScript files that represents the interface and/or data models contained within the file. For keeping things a bit simpler in this book, we’ll keep the interface and the implementation within the same file, and the file name will have the same name as the primary interface. In this case IItem.ts. (see the Naming Conventions section at the end of this book for more information)

NOTE: You are free to separate the code into multiple files and follow even a more stricter convention, i.e. some places might prefer to have only one declaration within one file. If that is the case, than you might have an Item.interface.ts for the interface and an Item.class.ts for the implementation (if any), or Item.type.tsif the code represent a type and so on (this might be even a better standard then the one we are following in this book, especially apps destined to grow very large)

Your directory structure should now look similar to this:

Let’s write an interface that represents one item that will be rendered in our Item component. Our interface will have three properties:

  • id: this is a unique number for each item in the list
  • name: is be a string containing the name of the item
  • selected: is be a boolean value that indicates if the item has been selected by the user

The code for your interface should look like this:

export interface IItem {
    id: number
    name: string
    selected: boolean
}

For now that is all we need. Since this will only represent a piece of data, we do not need to implement a class.

ItemsList Component

Now that we have our interface, we can finally leverage TypeScript type checking ability by modifying our items property on the items component from any[] to IItem[]. First, import a reference for IItem:

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator'
    import { IItem } from '@/models/items/IItem'</pre>

Then modify our items property declaration from any[] to IItem[]:

    export default class ItemsListComponent extends Vue {
        @Prop() items!: IItem[]
    }

The complete update code should look like this:

<template>
    <div>
        <h3>My Items:</h3>
        <ul>
            <li v-for="item in items" :key="item.id">
                {{ item.name }}
            </li>
        </ul>
    </div>
</template>

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator'
    import { IItem } from '@/models/items/IItem'

    @Component
    export default class ItemsListComponent extends Vue {
        @Prop() items!: IItem[]
    }
</script>

Make sure the terminal does not display any error, and that the web browser refreshed and no error are displayed in the browser console.

Home View

We should also update the Home.vue code so that it uses the IItem interface for the locally private property also called items:

<template>
    <div class="home">
        <ItemsListComponent :items="items" />
    </div>
</template>

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator'
    import ItemsListComponent from '@/components/items/ItemsList.component.vue'
    import { IItem } from '@/models/items/IItem'

    @Component({
        components: {
            ItemsListComponent
        }
    })
    export default class Home extends Vue {
        private items: IItem[] = [{
            id: 1,
            name: 'Item 1',
            selected: false
        }, {
            id: 2,
            name: 'Item 2’,
            selected: false
        }, {
            id: 3,
            name: 'Item 3',
            selected: false
        }]
    }
</script>

Again, make sure the terminal does not display any error, and that the web browser refreshed and no error are displayed in the browser console. As you make changes is also a good idea to occasionally do an Empty Cache and Hard Reload:

Chapter 3 Recap 

What We Learned

  • It’s important to follow files and directories naming convention and structure convention
  • How to leverage TypeScript interfaces and avoid using any so that strong-type checking is enforced at development time

Observations

  • The Home.vue contains a local property that holds hard-coded mocked data that enabled us to quickly prototype our component
  • ItemsList.component.vue just display the list of items, but the user has still no ability to click on them to change their selected property

Based on these observations, there are a few improvements that will be making into the next chapter:

Improvements

  • Update our component so that when a user clicks on an item displayed on the page, the item selected property will toggle from false to true (and vice versa)