Hey, hey, hey, hey, hey, hey, hey, hey, hey. I’m back.

This is the end of the TypeScript basics tutorial series, which will show you how to apply TypeScript to your projects to help those who don’t already know how.

Statement (or this statement) : โœจ this series of articles as the basis of the tutorial, does not involve deep things, more suitable for beginners to see, if the students have already met, read this paragraph of text can run away ๐Ÿ˜‹.

Used in Vue projects

While the previous two articles covered the basics and deeper stuff of TypeScript, this chapter shows you how to use it in Vue projects.

Project creation

Create a project directly using vue-CLI

Here are the steps:

1. Run Vuecli

2. Select an appropriate directory to create the project

3. Enter the project name, select package Manager, and enter git repository initialization content

4. Set the preset, if you have a suitable preset, you can set the preset, select manual

5. Select features, where TypeScript and Babel are mandatory and other features depend on the project:

6. Set the configuration, turn on class style component syntax (item 1), select ESLint to configure to ESLint+Standard (item 5), and turn on save time check and fix code

7. Create projects

8. Install plug-ins

Editor files support Settings

Take Webstrom as an example:

Go to Editor>File and COde Templates

Create a new code template, enter a name with the extension vue, select Reformat according to style, and select enable the template

Content area input:

<template lang="pug">
#[[$END$]]#
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
export default class ${COMPONENT_NAME} extends Vue {

}
</script>

<style  lang="stylus" rel="stylesheet/stylus" module>

</style>
Copy the code

After clicking Apply, select the template you created when creating a new file:

Because we chose class style syntax, we need to fill in the class name:

Modify ESLint, editor configuration

Modify the ESLint configuration file to support checking TypeScript files

Add the following code to the.eslintrc.js parserOptions option:

parser: '@typescript-eslint/parser'
Copy the code

Modify the editor configuration to support automatic code repair when saving

One of webstrom’s strengths is its support for various technologies, such as esLint checking code. Normally, we would need to check code from the command line, which is cumbersome, but Webstrom can configure ESLint, check for code that is not configured for ESLint in the editor, and support save time fixes. The configuration is as follows:

Modify declaration file

For our custom plug-ins, global methods, global variables, etc., TypeScript doesn’t know about them. To let TypeScript know about them, we can declare files that tell TypeScript, If we use $style in model style, we modify the shims-tsx.d.ts file and add the following code at the end of the line:

declare module 'vue/types/vue' { interface Vue { $style: { [key: string]: string; }; } interface VueConstructor { $style: { [key: string]: string; }; }}Copy the code

This is similar for other things

Use in components

Basic usage

Because you use class style to write JS in a component, you write it slightly differently, but essentially the same.

A component reference

Component references are made by passing the parameter components to the decorator @component

@Component({
  components: {
    MapLegend: () => import('@/components/legend/index.vue')
  }
})
Copy the code

The filter

Filters, like components, define local filters within the filters object by passing the filters parameter:

@Component({
  filters: {
    dateFormat (date:Date) {
      return dateFormat(date)
    }
  }
})
Copy the code

instruction

Local directives are like filters, passing the parameter directives via the @Component decorator:

@Component({
  directives:{
    focus: {
      inserted: function (el) {
        el.focus()
      }
    }
  }
})
Copy the code

props

Props is no longer defined as an object property, but as the @prop decorator, whose configuration content is passed in as a parameter:

@Component export default class Test extends Vue { @Prop({ type:String, default:'no name', required:false }) name! :string mounted(){ console.log(name) } }Copy the code

Synchronous version of props

Using @propSync, you can create a synchronous version of the props property (if the variable changes, the corresponding props property changes with it) :

@Component export default class Test extends Vue { @PropSync('name',{ type:String, default:'no name', required:false }) name! :string mounted(){ this.name='nichols' } }Copy the code

Listener (Watch)

Similarly, listeners are defined by the @watch decorator, which receives two parameters, the first to monitor which variable, and the second to other configurations:

@Component
export default class Test extends Vue {
  isShow=false
  @Watch('isShow',{
    deep:true,
    immediate:true
  })
  onIsShowChange(val:boolean,newVal:boolean){

  }
}
Copy the code

A listener can also be treated as a method call, executing its internal logic:

  mounted(){
    this.onIsShowChange(true,false)
  }
Copy the code

emit

Raising an event in a component to be listened to by the parent is a very common operation. The @emit decorator defines a function that can be called as a normal function:

@Component
export default class Test extends Vue {
  name = ''

  @Emit('change')
  onChange (name: string) {
    this.name = name
  }

  mounted () {
    this.onChange('nichols')
  }
}
Copy the code

If there is a return value, the return value is placed first as the triggered parameter, and the passed parameter is placed after the return value

ref

Define ref using the @ref decorator:

@Component export default class Test extends Vue { name = '' @Ref('form') form! :HTMLElement mounted(){ console.log(this.form.offsetHeight) } }Copy the code

data

For data within a component, we can define the component’s data directly using class attributes:

@Component
export default class Test extends Vue {
  isShow = false
  form: {
    username: string;
    password: string;
  } = {
    username: '',
    password: ''
  }

  mounted () {
    this.isShow = true
  }
}
Copy the code

Functions (Methods)

The data function is similar to the data definition, adding a method to the class:

@Component export default class Test extends Vue { log(){ // .... }}Copy the code

Calculate attribute

Compute properties, on the other hand, are written as accessors for classes (getters, setters, corresponding to Vue getters and setters) :

@Component export default class Test extends Vue {lastName = 'Nicholas' firstName =' Joe 'get name (): String {return '${this.firstName}ยท${this.lastName}'} set name (name: String) {const names = name.split('ยท') this.firstName = names[0] this.lastName = names[0]}}Copy the code

The life cycle

You can define the corresponding hook name directly, or use vue-class-Component /hooks. D.ts:

    @Component
export default class Test extends Vue {
  mounted () {
  }

  created () {
  }

  updated () {
  }

  beforeDestroy () {
  }

  destroyed () {
  }
}
Copy the code

More details

Refer to the VUe-property-decorator documentation for more details

Type declaration

Under the types directory of SRC, create index.d.ts (or more elaborate filename) and define the type, using the Event extension as an example:

interface Event{
  DataTransfer:{
    setData():void
  }
}
Copy the code

To avoid global variable clutter, we can use export to export declarations that we want to access externally:

export interface User{
  id:string;
  name:string;
  realName:string;
}
Copy the code

If you need to use it, import it in the place where you need to use it:

import { User } from '@/types/user'

@Component
export default class Test extends Vue {
  user:User={
    id: '',
    name: '',
    realName: ''
  }
}
Copy the code

Migration of old projects

Installing a plug-in

1. Launch vue UI (a shuttle is dry!) Click Add Plug-in in the Plug-in TAB.

2. Search for TypeScript, select @vue/ CLI-pluging-typescript, and click Install

Modify the components

1. Script tag add attribute lang=”ts”

2. Component import Add. Vue suffix

3. Change the default export to class style:

export default {
  name:'Component1'
}
Copy the code

Is amended as:

@Component
export default class Component1 extends Vue{
}
Copy the code

4. Change the corresponding data to the class style according to the basic usage

5. Add or modify type comments as prompted

Modifying js files

1. Change the extension of the js file to. Ts

2. Add type constraints

The use of vuex

Vuex and VUE components are used in a similar way, defined in the form of class style + decorators, using the dependency vuex-module-decorators,

The installation

yarn add vuex-module-decorators
npm i vuex-module-decorators
Copy the code

Create the Store

A Store is created in the same way as a regular Store:

import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
import getters from '@/store/getters'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters,
  modules: {
    User
  }
})
Copy the code

Definition module

@Module

Define a VUex Module using @Module that accepts the following parameters:

attribute

The data type

describe

name

string

The name of the module (if namespace exists)

namespaced

boolean

Whether the module has a namespace

stateFactory

boolean

Whether to enable the state factory (for module reuse)

dynamic

true

If this is a dynamic module (added to storage after storage is created)

store

Store

Store to inject into this module (for dynamic modules)

preserveState

boolean

If this option is enabled, the state is preserved when the module is loaded

Create a module with the following syntax:

import { VuexModule } from 'vuex-module-decorators'
@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
}
Copy the code

Note that the name of the module introduced in the Stroe constructor needs to be the same as the name specified in the decorator, otherwise the corresponding module will not be found

state

The definition of state is similar to that of data in the component:

@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
  token = getToken()
}
Copy the code

The above code has the same effect as the following:

export default {
    state:{
    token: getToken()
  },
  namespaced:true
}
Copy the code

@Mutation

Mutation is defined using the @mutation decorator:

@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }
}
Copy the code

@Action

Action is defined using the @Action decorator, which takes three arguments:

Parameter names

type

describe

commit

string

The load submitted

rawError

boolean

Whether to print the original error type (error messages are wrapped by default)

root

boolean

Whether root loads are allowed to be submitted

If no parameter is passed, the load needs to be submitted manually:

@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }

  @Action
  async login () {
    this.context.commit('setToken', 'token')
    router.replace('/')
  }
}
Copy the code

If the submitted load name is specified, the load value can be set by the return value of the function:

@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
  token = getToken()

  @Mutation
  setToken (token: string) {
    this.token = token
    token ? setToken(token) : deleteToken()
  }

  @Action({commit:'setToken'})
  async login ():string {
    router.replace('/')
    return 'token'
  }
}
Copy the code

@MutationAction

MutationAction decorator (@mutationAction) : mutatioin (@mutationAction) : mutatioin (@mutationAction) : MutationAction (@mutationAction) : mutatioin (@mutationAction)

@Module({
  name: 'User',
  namespaced: true,
  stateFactory: true
})
export default class User extends VuexModule {
  testStr = ''

  @MutationAction({ mutate: ['testStr'] })
  async setStr () {
    return new Promise<{ testStr: string }>(resolve => {
      resolve({
        testStr: 'test'
      })
    })
  }
}
Copy the code

Note that the data structure of the returned object must match the specified parameter name

getter

The definition and the Vue getter in the component attribute defines a similar calculation, using the get prior to the method name:

@Module
class MyModule extends VuexModule {
  wheels = 2

  get axles() {
    return this.wheels / 2
  }
}
Copy the code

Complete sample

import { deleteRefreshToken, deleteToken, deleteUserInfo, getRefreshToken, getToken, getUserInfo, setRefreshToken, setToken, setUserInfo } from '@/utils/auth' import { UserInfo } from '@/types/user' import router from '@/router' import { Action,  Module, Mutation, MutationAction, VuexModule } from 'vuex-module-decorators' @Module({ name: 'User', namespaced: true, stateFactory: true }) export default class User extends VuexModule { token = getToken() refreshToken = getRefreshToken() userInfo: UserInfo | null = getUserInfo() testStr = '' @Mutation setToken (token: string) { this.token = token token ? setToken(token) : deleteToken() } @Mutation setRefreshToken (token: string) { this.refreshToken = token token ? setRefreshToken(token) : deleteRefreshToken() } @Mutation setUserInfo (user: UserInfo | null) { this.userInfo = user user ? setUserInfo(user) : deleteUserInfo() } @MutationAction({ mutate: ['testStr'] }) async setStr () { return new Promise<{ testStr: string }>(resolve => { resolve({ testStr: 'test' }) }) } @Action async login () { this.context.commit('setToken', 'token') this.context.commit('setRefreshToken', 'refreshToken') this.context.commit('setUserInfo', {}) router.replace('/') } @Action async loginOut () { this.context.commit('setToken', '') this.context.commit('setRefreshToken', '') this.context.commit('setUserInfo', null) router.replace('/login') } }Copy the code

Use in components

GetModule (); getModule();

import { Component, Vue } from 'vue-property-decorator'
import User from '@/store/modules/user'
import { getModule } from 'vuex-module-decorators'

let user:User

@Component
export default class test extends Vue {
  login ():void {
    console.log(user.testStr)
    user.login()
  }

  mounted ():void {
    user = getModule(User, this.$store)
  }
}
Copy the code

Used in small programs

It’s easy to use TypeScript in applets. Choose TypeScript as the language when creating projects, and the rest are similar to Vue projects

Unlike Vue projects that compile TypeScript automatically, applets need to compile TS files manually, which is a bit of a hassle, so we can use Webstrom to develop applets:

Install the applets plug-in and let Webstrom support applets syntax: File>Setting>Plugins, search for Wechat Mini programs upport, and restart Webstrom.

Set ts files to compile automatically: File>Setting>Languages & Frameworks>TypeScript

conclusion

This series of articles is written in conjunction with the project. If you want to learn more about TypeScript, check out the following sites:

TypeScript Chinese website

TypeScript tutorial

TypeScript learning resources collection

This article may not be comprehensive, incorrect or difficult to understand, feel free to comment in the comments section ๐Ÿ˜Š๐Ÿ˜Š

In the meantime, everyone, spray gently, after all:

I’m a character eight nickname, we’ll see you in other series