Skip to content

TypeScript

TIP

Recommend to familiarize yourself with Using Vue with TypeScript before reading this section.

A type system like TypeScript can detect many common errors via static analysis at build time. This reduces the chance of runtime errors in production, and also allows us to more confidently refactor code in large-scale applications. Vitify Admin comes with full TypeScript support. All application code, testing code and configuration are written in TypeScript except eslintrc which does not support TypeScript and public/mockServiceWorker.js which is a worker file auto generated by Mock Service Worker. Third-party components without component type definition like PortalVue and Vuetify 2 have already been shimed in this template.

Manually Define Component Types

Vitify Admin is a Vue 2 template. As Vue 2 is poor in TypeScript support before Vue 2.7, almost all Vue 2 components have no type support. Now with the power of Volar, we can profit type check and type-based auto-completion in SFC template. Here is how to define component props and slots manually to get intellisense in IDE:

ts
import type { DefineComponent, VNode } from '@vue/runtime-dom'

declare module '@vue/runtime-dom' {
  export interface GlobalComponents {
    MyComponent: DefineComponent<
      Props,
      {
        $scopedSlots: {
          slotName: ({args: {propName: propType}}) => VNode[]
        }
      },
    >
    // or
    MyComponent: DefineComponent<
      Props,
    > & new () => {
      $scopedSlots: {
        slotName: (_: { propName: any }) => VNode[]
      }
    }
  }
}
import type { DefineComponent, VNode } from '@vue/runtime-dom'

declare module '@vue/runtime-dom' {
  export interface GlobalComponents {
    MyComponent: DefineComponent<
      Props,
      {
        $scopedSlots: {
          slotName: ({args: {propName: propType}}) => VNode[]
        }
      },
    >
    // or
    MyComponent: DefineComponent<
      Props,
    > & new () => {
      $scopedSlots: {
        slotName: (_: { propName: any }) => VNode[]
      }
    }
  }
}

We can also add component methods, but we rarely need type check and auto-completion of component methods in SFC template.

ts
import type { DefineComponent, VNode } from '@vue/runtime-dom'

declare module '@vue/runtime-dom' {
  export interface GlobalComponents {
    MyComponent: DefineComponent<
      Props,
      {
        $scopedSlots: {
          slotName: ({args: {propName: propType}}) => VNode[]
        }
      },
      {},
      {},
      Methods
    >
    // or
    MyComponent: DefineComponent<
      Props,
      {},
      {},
      {},
      Methods
    > & new () => {
      $scopedSlots: {
        slotName: (_: { propName: any }) => VNode[]
      }
    }
  }
}
import type { DefineComponent, VNode } from '@vue/runtime-dom'

declare module '@vue/runtime-dom' {
  export interface GlobalComponents {
    MyComponent: DefineComponent<
      Props,
      {
        $scopedSlots: {
          slotName: ({args: {propName: propType}}) => VNode[]
        }
      },
      {},
      {},
      Methods
    >
    // or
    MyComponent: DefineComponent<
      Props,
      {},
      {},
      {},
      Methods
    > & new () => {
      $scopedSlots: {
        slotName: (_: { propName: any }) => VNode[]
      }
    }
  }
}

Refers to components.d.ts and vuetify2.d.ts for detailed examples.

Vuetify Component Types

One of the main feature of this template is Vuetify 2 component types. As Vuetify 2 does not support Volar officially and types of all components are just VueConstructor without any further details, I tried generating component type definition from web-types of Vuetify 2 which is used to build documentations. It works like a charm. We now have type check for props and slots in Vuetify 2 components in template block of SFC. Types for Vuetify all over the place!

The script used to generate Vuetify components type is located in scripts folder. It is added in package.json. You can run it to get the latest types once the web-types of Vuetify 2 is updated.

json
// package.json
"scripts": {
  /* ... */
  "type:vuetify": "node ./scripts/vuetify-type.mjs > ./src/vuetify2.d.ts"
},
// package.json
"scripts": {
  /* ... */
  "type:vuetify": "node ./scripts/vuetify-type.mjs > ./src/vuetify2.d.ts"
},

Project Reference

In Vitify Admin, we use Project References to ensure correct types for code running in different environments. For example, app code and test code should have different global variables. While Vitest spec files are run in Node.js where we need @types/node, app code run in browsers should not include types of node. Project References also prevent developers from accidentally importing app source file into vite.config.ts which results into server restart instead of HMR once the source file is changed.

We can use the vue-tsc utility for command line type checking. Here we have already set the command for checking type of app code by specifying the particular tsconfig file.

json
// package.json
"scripts": {
    /* ... */
    "typecheck": "vue-tsc --noEmit -p tsconfig.app.json --composite false"
  },
// package.json
"scripts": {
    /* ... */
    "typecheck": "vue-tsc --noEmit -p tsconfig.app.json --composite false"
  },

Just run

sh
pnpm typecheck
pnpm typecheck

Released under the MIT License.