Advantages of using typescript

There is a question that cannot be avoided when talking about TS: why use TS and what advantages do you have over JS? Let me try to answer this question in two ways:

1.1 Convenience in project development

  1. Avoid low-level bugs

I believe you have encountered an embarrassing rolleover scene in the editor operation, open the browser page blank, and then a debug finally found that the variable name is misspelled, after using TS, there will be no such trouble, similar error editor immediately prompt you:

  1. Editor intelligent hints

Project becomes more and more large, remember that a variable description of what is also a very difficult thing, may be we need to constantly to find the type definition, in fact ts can well solve this problem, although the start type definition a bit tedious, but he brings type hinting, code completion, etc. Will let us feel the effort is worth it.

1.2 Maintenance cost of the later project

  1. Types are comments

In our work, it is inevitable that we need to upgrade or modify a certain module, and sometimes we need to read the code if there are no comments or incomplete comments. In fact, most of the time, we do not care about the specific implementation of a module, we just want to know its input and output. In this case, TS is suitable for this scenario:

type Pay = (orderId: string) = > Promise<-1 | 0>

const pay: Pay = orderId= > {
  // do something
}
Copy the code

Similar to the code above, the purpose can be roughly inferred from the type definition

  1. To reconstruct

This may be a big advantage of the type system. In the past, when refactoring A JS project, it can be said that you are walking on thin ice, for fear of crashing the whole project after changing a module. With the type system, you can feel much more secure.

2. Let the type flow

Usually we add type definitions to the interfaces in the project, which is probably the most tedious part. Suppose we have an interface to get information about a product as follows:

// goodApi.ts
export type GoodInfo = {
  infoId: string,
  price: string,
  title: string,
  label: {
    labeltxt: string,
    labelImg: string
  }[]
}

const getGoodInfo = (): GoodInfo[] => {
  // do something
}
Copy the code

There is now a method processLabel that needs to input the item’s label to do something with labelImg, as follows:

type LabelMsg = {
  labeltxt: string,
  labelImg: string
}[]

const processLabel = (labelArr: LabelMsg) = > {
  // do something
}
Copy the code

Obviously labelArr is derived from the label of GoodInfo, so a better approach is to reuse the types in GoodInfo:

import { GoodInfo } from './goodApi.ts'

const processLabel = (labelArr: GoodInfo['label']) = > {
  // do something
}
Copy the code

Of course, the scenarios we encountered could not all be so simple, and there might be a complex point where the function processLabel depends on the data returned from two or more interfaces:

import { GoodInfo } from './goodApi.ts'
import { UserInfo } from './userApi.ts'

type Info = Pick<GoodInfo, 'label'> & Pick<UserInfo, 'tag | avatar'>
const processLabel = (info: Info) = > {
  // do something
}
Copy the code

In conclusion, WHAT I want to say is that we should try to reuse types or use type derivation instead of blindly declaring new types, which will bring some convenience in late project maintenance or code refactoring.

3 [email protected] use of ts

Ok, moving on to the topic of this article, using TS in Vue, a regular component in Vue might look like this:

export default {
  template: ''.data() {
    return {
      preStr: 'Hello! '}},props: {
    message: {
      type: String.default: 'world'}},methods: {
    onClick () {
      window.alert(this.preStr + this.message)
    }
  }
}
Copy the code

[email protected] ts is usually used in the vue-property-decorator library. Let’s take a look at how it works:

import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator';

@Component({
  template: ''
})
export default class Test extends Vue {
  preStr: string = 'Hello! '

  @Prop({ type: String.default: 'world' })
  message: string

  onClick (): void {
    window.alert(this.preStr + this.message)
  }
}
Copy the code

You can see that you need to convert object literals to class-based component definitions. This makes it easy to add types to the component’s state, prop, method, and so on. It also uses decorators to export standard VUE components at run time. Let’s take a look at the inner workings of the Component decorator:

export function componentFactory (
  // Component is the defined Component class
  Component: VueClass<Vue>,
  // Options is the initial option passed to the Component decorator
  options: ComponentOptions<Vue> = {}
) :VueClass<Vue> {
  options.name = options.name || (Component as any)._componentTag || (Component as any).name

  const proto = Component.prototype
  Object.getOwnPropertyNames(proto).forEach(function (key) {

    // If the method name has the same name as the vue lifecycle, put it directly into options
    if ($internalHooks.indexOf(key) > -1) {
      options[key] = proto[key]
      return
    }
    const descriptor = Object.getOwnPropertyDescriptor(proto, key)
    // Insert normal methods into options' methods
    if(descriptor.value ! = =void 0) {
      if (typeof descriptor.value === 'function') {
        (options.methods || (options.methods = {}))[key] = descriptor.value
      }
    // The get set function is placed into the options computed
    } else if (descriptor.get || descriptor.set) {
      (options.computed || (options.computed = {}))[key] = {
        get: descriptor.get,
        set: descriptor.set } } }) ; (options.mixins || (options.mixins = [])).push({ data (this: Vue) {
      // The properties on the class instance are treated as the return value of the data function in Options, which is state
      return collectDataFromConstructor(this, Component)
    }
  })

  // Super extends a regular Vue component based on the options calculated
  const Extended = Super.extend(options)

  return Extended
}
Copy the code

The Component decorator is basically a collection of Component class prototype methods, which are distributed to options’ lifecycle methods, common methods, and computed properties based on different conditions, and then a collection of class instance properties as the return value of the data function in Options. Finally, extend a standard VUE component according to options.

Here’s a quick look at how Prop decorators work:

export function Prop(options: PropOptions | Constructor[] | Constructor = {}) {
  return (target: Vue, key: string) = > {
    applyMetadata(options, target, key)
    createDecorator((componentOptions, k) = > {
      // componentOptions = "componentOptions"; (componentOptions.props || ((componentOptions.props = {})as any))[
        k
      ] = options
    })(target, key)
  }
}
Copy the code

The Prop is simple. You put the key-value pair of the Prop’s decorated key and the passed parameters into options.props. Similarly, the vue-property-decorator provides many other decorators (Model, Watch, Ref, etc.). Covers common usage scenarios, with the basic principle of modifying the options parameter of the construct component at run time.

4 [email protected] use of ts

[email protected] has been released, bringing Composition Api and better typescript support. For [email protected] + ts projects, you can infer the type in Component Options perfectly by simply defining the component with defineComponent:

import { defineComponent } from 'vue'

const Component = defineComponent({
  data() {
    return {
      preStr: 'hello! '}},props: {
    message: {
      type: String.required: true}},methods: {
    onClick() {
      this.preStr = 'hi! ' // ok preStr is inferred to string
      this.preStr = 123   // Error The number type cannot be assigned to string
      this.message = 'zz' // Error Message is the read-only attribute}}})Copy the code

Support for the Composition Api is also high:

import { defineComponent, ref, PropType } from 'vue';

export default defineComponent({
  props: {
    callback: {
      required: true.type: Function as PropType<(nums: number) = > void>},message: {
      type: String.required: true}},setup(props) {
    const nums = ref(0)

    props.callback(props.message)  // The argument to the error callback should be of type number

    props.callback(nums.value)     // ok}})Copy the code

I have also tried using TS in [email protected] through a demo, which is quite smooth. Compared to the class-based component definition in [email protected], [email protected] does not require us to change any code habits to easily access TS, and its type derivation is quite powerful.

At the end of the day, Vue template writing is not compatible with TS, although there is an alternative to TSX, but it is not Vue, but I believe there will be good tools to make up for this. All in all, Vue’s support for TS is strong enough, let’s use it, it smells good!

The welfare of

Article in the “big turn FE” public number will be sent, and the public number has a raffle, this article prize is around a commemorative T-shirt, welcome to pay attention to the ✿✿ angry (°▽°) Blue