Summary of experience in the typescript transformation process of old vue2.x projects

Foreword:

Regarding the TS transformation of Vue2.x, there is actually nothing much to say.

For the vue-cli project, run vue create xxx-project again, select Manually select features, and re-select the typescript option. Or you can directly vue add typescript.

There is too much information on the Internet, so here are some recommendations that I think are pretty good (I did it myself, so I don’t think it’s difficult personally, haha)

For webpack, just add ts-loader, then add tsconfig.json, configure ts attributes, and then add ts code specifications in eslint. Then just change the old project file to a ts file and it will be fine. That’s it. ^_^ After all, it’s 2021 now (TS has been popular for many years after all), and there are too many tutorials.

Project configuration notes:

This article talks about some precautions required, as well as the similarities and differences of some implementation methods, as well as my own opinions (please leave a message before making any mistakes, thank you)

WebPack configuration modification

  • Add TS suffix: extensions: ['.js', '.vue', '.json', '.ts'], 

  • 增加ts-loader: {test: /\.ts$/, loader: 'ts-loader', exclude: /node_modules/, options: {appendTsSuffixTo: [/\.vue$/],}}

TypeScript configuration file

Create the tsconfig.json file in the project root directory. You need to pay attention to the following configurations:

  • " strictPropertyInitialization ": false, // strict defaults to true - you must ensure that the properties of each instance will have an initial value

  • " noImplicitAny ": false, // false means running the implicit any type, which means that no type is allowed to be set. This setting runs the js file and directly changes it to the ts file.

  •  " allowJs ": true, // In the initial transformation, JS and TS must run in parallel.

  • " strictFunctionTypes ": false, // This option needs to be turned on to enable vuex-class

  • " target ": "es5", // Compile and output the target ES version

  • "skipLibCheck": true,

  •  " jsx ": "preserve", // Support JSX in .tsx files

  • " experimentalDecorators ": true, // enable decorators

  •  " strictNullChecks ": true, // When you declare a variable, it will not automatically contain null or undefined.

For everything else, just follow the official ones.

I think noImplicitAny is a bit of a hacky way of playing, but if you're revamping an old project, you can make changes and adjustments as you go. Otherwise, if you change it again and again, you will lose confidence in reconstruction.

Add TS configuration items to eslint parsing rules

In the root directory, .eslintrc.js, reference configuration

extends: [
  'plugin:vue/recommended',
  'eslint:recommended',
  '@vue/typescript/recommended',
  '@vue/prettier',
  '@vue/prettier/@typescript-eslint'
],
parserOptions: {
  ecmaVersion: 2020,
},

In fact, this configuration is up to you. By default, the file generated by vue-cli is fine. If there is no vue-cli, a demo project will be generated. Make a copy. Of course we have to follow the internal code specifications of Goose Factory, so we won’t post it.

TypeScript declaration file

Official documentation: Introduction · Declaration file · TypeScript Chinese website · TypeScript - a superset of JavaScript

import Vue, { VNode } from 'vue';
declare global {
  interface Window { // 全局变量
    i18n: any;
    eCharts: any;
  }
}
declare module 'vue/types/vue' {
  interface Vue {
    $bus: Vue;
    $route: any;
    $router: any;
    CancelToken: any;
    $message: any;
    $confirm: any;
  }
}
declare global {
  namespace JSX {
    interface Element extends VNode {}
    interface ElementClass extends Vue {}
    interface IntrinsicElements { [elem: string]: any; }
  }
}

The project transformation is basically over here.

TS some notes

In this part, members need to be reminded of things that have just been renovated.

TS type

any

Any, this thing is easy to use, but if you let it go completely, believe me, it will probably end up being any.

However, in the early stage of project transformation, you can replace it with any first, and you can further refine it later when you have time. This metric is actually not very easy to measure. For novices, when merging code, it is better to return it to any.

Optional properties vs null undefined

Null and undefined are the basic types in ts, with values ​​null and undefined respectively. By default, they are subtypes of all types, that is, they can be assigned to any type .

null and undefined are a valid value for all other types. This also means that you can't prevent them from being assigned to other types, even if you wanted to.

The inventor of null, Tony Hoare, calls it the billion-dollar mistake.

When strictNullChecks is set to true in the tsconfig.js file, null and undefined cannot be assigned to any type except themselves and void.

In the case of this strict check, if you really want to set the initial value to NULL for a value of another type somewhere and then assign it to a value, you can use a union type to achieve this.

let test: string | null = 'hi'

There is a difference between null and undefined

string|undefined, string|null and string|undefined|null are three different types .

If "strictNullChecks": true is set, optional parameters will be automatically added|undefined

let test?: string = 'hi'

interface/class/abstract class/type

Declaration Type Namespace Type Value
Namespace X X
Class X X
Enum X X
Interface X
Type Alias X
Function X
Variable X

Not counting symbols, there are 6 basic types in js, number, string, boolean, null, undefined, and object. But relying only on these types to describe what parameters a function needs to pass is far from enough. This is also the mission of the interface - to describe the shape (type) of a value (value).

First of all, class also has the ability of interface, describing a shape, or representing a type. In addition, class also provides implementation, which means it can be instantiated;

Interface can extend class, and the class at this time assumes the role of type. This is a bit WTF for me who used to write java. In fact, undefined has its own type called undefined, and Java programmers are also confused.

TypeScript reflects the dynamic nature of JavaScript by employing a structured type system and does an excellent job of type inference, which means you don't have to express types explicitly like C# or Java.

One of the design goals of TypeScript is not to create a "correct type system" but to "strike a balance between correctness and productivity." ——The TypeScript compiler will not force you to declare types, and it is up to you to decide the degree of type safety. You can even decide to apply different levels of type safety strictness to different areas of your project. This kind of flexibility is not something traditional statically typed languages ​​can provide.

I don’t want to talk too much here. I think the typescript manual is very detailed: Basic types · TypeScript Chinese website · TypeScript - a superset of JavaScript

Comparison of Vue upgrade plans

There are many options for upgrading vue2 to TS.

Traditional solution: vue-property-decorator

Vue2 supports ts mainly through vue class component. Here we mainly rely on decorators. Please read " From Java Annotation Comics to TypeScript Decorators - Annotations and Decorators ".

In addition, you can expand your understanding of metaprogramming.

The most criticized aspect of vue2 is its support for ts. Poor support for ts is an important reason why vue2 is not suitable for large projects. The fundamental reason is that Vue relies on a single this context to expose properties, and this in Vue is more magical than in ordinary JavaScript (for example, this in a single method under the methods object does not point to methods, but to the vue instance). In other words, You Dada did not consider support for ts references when designing the Option API)

The specific usage is relatively detailed: GitHub - kaorun343/vue-property-decorator: Vue.js and Property Decorator

  
       

I personally don't like this style very much, but it is used everywhere, and now the refactoring project adopts this style.

typescript mixin

I'm not a big fan of mixins. Since you want to use it, you must pay attention to the following points:

Mixins merging rules:

  • Covered: data, props, methods, computed, inject

  • Direct replacement: el, template, propData

  • combined:

    • methods, functions with high weight are executed first

    • Life cycle function, watch monitoring callback function, the smaller weight is executed first

mixins mix weight

Similar to CSS weight rules (actually there is no such thing as weight, but the result is the same, I just think it is easier to understand)

  • *, global options

  • 1. ...omit countless possible nested mixins

  • 10、Setup - mixin - mixin

  • 100. Component-mixin

  • 1000. Component options

For more information, see " Notes on Notes on Using Vue Mixins, Vue.extend(), and Extends "

It's very simple to use

import { Component, Mixins, Vue } from 'vue-property-decorator';
// mixin
@Component
export default class PageLeave extends Vue {
  // TODO
}
// 组件
@Component({
  components: {
    TitleBar,
  },
})
export default class CardPanel extends Mixins(PageLeave,OtherMixin) {
  //TODO
}

However, I have basically excluded mixin from TS’s vue project.

Back in mid-2016, Dan Abramov wrote Mixins Considered Harmful, in which he argued for the use of mixins for reusing logic in React components. is an anti-pattern and advocates staying away from them.

The shortcomings he mentioned about React mixins also apply to Vue.

OPP can solve everything, isn't it great?

Disadvantages of the vue-property-decorator solution

  • The vue class component is too different from the vue component of js. In addition, additional libraries need to be introduced, which greatly increases the learning cost.

  • Depends on decorator syntax. At present, the decorator is still in the stage 2 stage (see tc39 decorators), and there are still many uncertainties in the implementation details, which makes it a quite dangerous foundation.

  • Increased complexity. Using Vue Class Component requires the use of additional libraries, which is obviously more complicated than simple js vue components.

Personally, I prefer the next plan.

tsx combination solution: Vue Components + TypeScript

I wrote react at first, and then vue, so I prefer this style.

import Vue, { VueConstructor, CreateElement, VNode } from 'vue';
interface InputInstance extends Vue {
  composing: boolean;
}
export default (Vue as VueConstructor).extend({
  name: 'demo-input',
  props: {},
  data() {},
  // TODO 更Vue其它组件一样
  render(h: CreateElement): VNode {
    // TODO 逻辑
    const classes = []
    const wrapperAttrs = {...this.$attrs};
    const wrapperEvents = {...this.$listeners};
    // JSX 语法
    return (
      
               

      );   } }

The mixin here is still the same as before

// Count.mixin.ts
import Vue from 'vue'
import { mapGetters } from 'vuex'
export default Vue.mixin({
  computed: {
    ...mapGetters(['count'])
  },
  methods: {}
})
// Count.vue
export default Vue.extend<{}, Methods, Computed, {}>({
  mixins: [CountMixin],
  methods: {}
})

Multiple mixins

import CountMixin, { Computed as CountComputed } from './Count.mixin'
import LoadingMixin, { Computed as LoadingComputed } from './Loading.mixin'
type Computed = CountComputed & LoadingComputed
interface Methods {
  incrementCount: Function
  decrementCount: Function
}
export default Vue.extend<{}, Methods, Computed, {}>({
  mixins: [CountMixin, LoadingMixin],
  methods: {}
})

However, the data type of the mixin above is unclear...

Recommended implementation

interface CountBindings extends Vue {
  count: number
}
export default (Vue as VueConstructor).extend({
  mixins: [CountMixin],
  methods: {}
})

For details, please refer to https://medium.com/glovo-engineering/vue-components-typescript-ff62db05829c

composition-api

This first requires npm i -S @vue/composition-api

Then inject globally

import VueCompositionApi from "@vue/composition-api";
Vue.use(VueCompositionApi);

Actually, I am also thinking about this. Will add more content on this later.

Directly upgrade Vue3.0

I haven't done it yet. If it is a rewrite and reconstruction, I will definitely use Vue3.0 directly. But for huge projects, it is still scary to refactor directly to use 3.0.

Although Youda said that vue2 and vue3 will not be as different as angular2 and its descendants, I still take it easy.

The pain of Vuex Store

Using vuex in ts is very painful.

The two libraries related to the vuex ts version, vuex-class and vuex-module-decorators, should be the most used at present (in my opinion).

https://www.npmtrends.com/vuex-aggregate-vs-vuex-class-vs-vuex-module-decorators

stars issues updated created
vuex-class 1,653 18 Oct 12, 2020 Jan 14, 2017
vuex-module-decorators 1,595 123 May 8, 2021 May 1, 2018

If it is an old project, I personally recommend using vuex-class first.

I’ll sort it out here for now and go to bed early on the weekend. Will follow up later...

When reprinting this site's article " Experience Summary of Typescript Transformation Process of Old Vue2.x Projects ",
please indicate the source: https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8637.html

Guess you like

Origin blog.csdn.net/u012244479/article/details/118229363