In the first project to use Vue TypeScript, what to do

Foreword

As we know, Vue new version 3.0 uses TypeScript development, so inherently fire TypeScript be more people's attention. Although TypeScript only fire in recent years, but in fact it was born in October 2012, the official version was released in June 2013, it was written by Microsoft's free and open source programming language. TypeScript is a superset of JavaScript, JavaScript syntax expansion, add the optional statically typed object-oriented programming and class-based.

JavaScript error is often encountered in the development of variable or attribute does not exist, but these are low-level errors, and static type checking can just make it up. What is statically typed? For chestnut:

//javascript 
let str = 'hello'
str = 100 //ok

//typescript
let str:string = 'hello'
str = 100 //error: Type '100' is not assignable to type 'string'.

We can see TypeScript need to add a variable of type when you declare a variable, if the variable value and type of inconsistency will throw a warning. Only static type checking at compile time, and eventually compiled code is still JavaScript. Even if we assigned to other types of variables of type string, the code can also normal operation.

Secondly, TypeScript increase the readability and maintainability of the code, type definition is actually a very good document, such as when using a function, only need to look at the type defined parameters and return values, you probably know how this function jobs.

table of Contents

Ready to work

asl

Installation typescript

npm install typescript @vue/cli-plugin-typescript -D

New file

Shims-vue.d.ts created in the root directory of the project, shims-tsx.d.ts, tsconfig.json

  • shims-vue.d.ts
import Vue from 'vue';

declare module '*.vue' {
  export default Vue;
}
  • shims-tsx.d.ts
import Vue, { VNode } from 'vue';

declare global {
  namespace JSX {
    type Element = VNode
    type ElementClass = Vue
    interface IntrinsicElements {
      [elem: string]: any;
    }
  }
}
  • tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators":true,
    "sourceMap": true,
    "noImplicitThis": false,
    "baseUrl": ".",
    "types": [
      "webpack-env"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

ESLint Configuration

Why ESLint instead TSLint?

In January this year, TypeScript official release blog recommended ESLint instead TSLint. The ESLint team will no longer be maintained typescript-eslint-parser, it will not be published on Npm, any use of tyescript-eslint-parserthe user should switch @tyescript-eslint/parser.

The official explanation:

There are some structural problems affect the performance of the system we noticed TSLint rules of operation, ESLint already have linter we hope to get from the higher-performance architecture. In addition, different user communities usually have lint rules for ESLint instead TSLint constructed (for example, the rules React hook or Vue). In view of this, our editorial team will focus on the use of ESLint, instead of copying the work. For scenes (such as linting semantic linting or program-wide) ESLint currently not covered, we will work to support and TSLint ESLint of TypeScript equated.

original

how to use

AlloyTeam provides a comprehensive set of EsLint configuration specifications for React / Vue / Typescript project, and can customize the rules on this basis.
GitHub

installation

npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-alloy

Details Item View AlloyTeam ESLint rules

Configuration

.Eslintrc.js created in the root directory of the project, and then copy the following into it:

module.exports = {
  extends: [
    'alloy',
    'alloy/typescript',
  ],
  env: {
    browser: true,
    node: true,
  },
  rules: {
    // 自定义规则
    'spaced-comment': 'off',
    '@typescript-eslint/explicit-member-accessibility': 'off',
    'grouped-accessor-pairs': 'off',
    'no-constructor-return': 'off',
    'no-dupe-else-if': 'off',
    'no-import-assign': 'off',
    'no-setter-return': 'off',
    'prefer-regex-literals': 'off'
  }
};

supplement

If you want to know more configuration items used to be ESLint official website search configuration items.

If you are using VScode, we recommended ESLint plug-in supporting development.

File transformation

Entry file

  1. main.js changed main.ts
  2. vue.config.js modify entry file
const path = require('path')
module.exports = {
  ...
  pages: {
    index: {
      entry: path.resolve(__dirname+'/src/main.ts')
    },
  },
  ...
}

vue component files

With TypeScript and ES6 introduced in class, in some scenarios we need additional features to support labeling or modify the class and its members. Decorator (Decorators) provides a way for us to add annotations on the statement by the members of the class and meta-programming syntax.

Vue also provides us with TypeScript decorator class style assembly, it is necessary to experimentalDecorators tsconfig.json set to true before using the decorator.

Installation vue decorator

vue-property-decoratorLibrary is fully dependent on vue-class-componentbeing fitted together during installation

npm install vue-class-component vue-property-decorator -D

Transformation .vue

Only need to modify something in the srcipt, other unwanted changes

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

@Component({
  created(){
    
  },
  components:{
    draggable
  }
})
export default class MyComponent extends Vue {
  /* data */
  private ButtonGrounp:Array<any> = ['edit', 'del']
  public dialogFormVisible:boolean = false
  
  /*method*/
  setDialogFormVisible(){
    this.dialogFormVisible = false
  }
  addButton(btn:string){
    this.ButtonGrounp.push(btn)
  }

  /*compute*/
  get routeType(){
    return this.$route.params.type
  }
}
</script>

Class members modifier, without the addition of modifier it defaults to public

  • Members of the public can freely access the class: public
  • protected: protection, class and subclass inherits accessible
  • private: private, only the class can access

Prop

!: Use a clear assignment assertion modifier for the property, look for more documents

import { Component, Vue, Prop } from "vue-property-decorator";
export default class MyComponent extends Vue {
  ...
  @Prop({type: Number,default: 0}) readonly id!: number
  ...
}

Equivalent to

export default {
  ...
  props:{
    id:{
      type: Number,
      default: 0
    }
  }
  ...
}

Watch

import { Component, Vue, Watch } from "vue-property-decorator";
export default class MyComponent extends Vue {
  ...
  @Watch('dialogFormVisible')
  dialogFormVisibleChange(newVal:boolean){
    // 一些操作
  }
  ...
}

Equivalent to

export default {
  ...
  watch:{
    dialogFormVisible(){
      // 一些操作
    }
  }
  ...
}

Provide/Inject

// App.vue
import {Component, Vue, Provide} from 'vue-property-decorator'
@Component
export default class App extends Vue {
  @Provide() app = this
}

// MyComponent.vue
import {Component, Vue, Inject} from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
  @Inject() readonly app!: Vue
}

Equivalent to

// App.vue
export default {
  provide() {
    return {
      'app': this
    }
  }
}

// MyComponent.vue
export default {
  inject: ['app']
}

More decorative use, reference vue-property-decorator document

Global declarations

* .D.ts file

Current mainstream libraries are written in JavaScript, TypeScript as a superset of JavaScript, type definitions to support these libraries, provides a type definition files (* .d.ts), developers write to the type definition files released npm, when the user needs to use the library TypeScript project, you can additionally download this package, let JS library to run in TypeScript project.

For example: md5I believe many people have used this library can be converted to string a bunch of hash values, this transformation is not reversible, commonly used in sensitive information is hashed and then sent to the back-end verification to ensure data security. If we want to use in TypeScript project, we also need to download another @tyeps/md5, as can be seen in index.d.ts the folder md5defined type.

/// <reference types="node" />

declare function md5(message: string | Buffer | Array<number>): string;

declare namespace md5 {}

export = md5;

How TypeScript is to identify * .d.ts

TypeScript will automatically recognize the global project compile time .d.ts file, we need to do is write .d.ts, then TypeScript will these type definitions provided written injected into the global use.

Examples of vue add properties / methods

When we use this.$routethe time or some of the ways the prototype, typescript not be inferred, will be reported at compile time property $routedoes not exist error, we need to add global declarations for these global properties or methods

Make changes to the shims-vue.d.ts, of course, you can also choose to add custom * .d.ts statement

import Vue from 'vue';
import VueRouter, { Route } from 'vue-router'

declare module '*.vue' {
  export default Vue;
}

declare module 'vue/types/vue' {
  interface Vue {
    $api: any;
    $bus: any;
    $router: VueRouter;
    $route: Route;
  }
}

Custom Type Definition files

While some types of interfaces and other frequently needed, we can write for the project global type definitions,
create @types folder root path, which kept * .d.ts file, specifically for the type definition file management project.

Here I define a global.d.ts file:

//declare 可以创建 *.d.ts 文件中的变量,declare 只能作用域最外层
//变量
declare var num: number;

//类型
type StrOrNum = string | number

//函数
declare function handler(str: string): void;

// 类
declare class User { 
  
}

//接口
interface OBJ {
  [propName: string]: any;
  [propName: number]: any;
}

interface RES extends OBJ {
  resultCode: number;
  data: any;
  msg?: string;
}

Hands free, transvue2ts conversion tool

Transformation process is the most troublesome is the syntax conversion, fixed content are some of the wording, the work can be repetitive and boring machine to do it. Here we can make use of transvue2ts tools to improve efficiency, transvue2ts will help us put data, prop, watch and other grammar convert decorator syntax.

installation

npm i transvue2ts -g

use

After installation, the path will be written to the path transvue2ts library system, the direct command-line tool can be used to open the second parameter is the full path of the command file.
After executing the command will be generated in the same directory the converted new file, such as processing index.vue view folder after the conversion will generate indexTS.vue.

Single-file assembly process

transvue2ts D:\typescript-vue-admin-demo\src\pages\index.vue
=>
输出路径:D:\typescript-vue-admin-demo\src\pages\indexTS.vue

Vue handle all component files under the folder

transvue2ts D:\typescript-vue-admin-demo\src\pages
=>
输出路径:D:\typescript-vue-admin-demo\src\pagesTS

supplement

Do not think there really is completely hands free tool, but tools to help us convert part of syntax. Tools could not handle the syntax and parameters of type definitions, or we need to modify. Note that the converted annotation will be filtered out.

The tool of the Nuggets introduce and implement ideas for tools

About using third-party libraries

Some tripartite library during installation, contains a type definition files without having to define their own use, it can be used directly type definitions provided by the official.

node_modules find the corresponding package folder, file type usually stored in a folder types, in fact, as the document type definition file, these contents can clearly see the required parameters and parameter types.

Here are some examples of the use of the library in the tripartite Vue in:

element-ui component parameters

Use type definitions

import { Component, Vue } from "vue-property-decorator";
import { ElLoadingComponent, LoadingServiceOptions } from 'element-ui/types/loading'

let loadingMark:ElLoadingComponent; 
let loadingConfig:LoadingServiceOptions = {
  lock: true,
  text: "加载中",
  spinner: "el-icon-loading",
  background: "rgba(255, 255, 255, 0.7)"
};

@Component
export default class MyComponent extends Vue {
  ...
  getList() {
    loadingMark = this.$loading(loadingConfig);
    this.$api.getList()
      .then((res:RES) => {
        loadingMark.close();
      });
  }
  ...
}

element-ui / types / loading, there are still many original document annotation, description will be made for each attribute

export interface LoadingServiceOptions {
  target?: HTMLElement | string
  body?: boolean
  fullscreen?: boolean
  lock?: boolean
  text?: string
  spinner?: string
  background?: string
  customClass?: string
}
export declare class ElLoadingComponent extends Vue {
  close (): void
}
declare module 'vue/types/vue' {
  interface Vue {
    $loading (options: LoadingServiceOptions): ElLoadingComponent
  }
}

vue-router hook function

Use type definitions

import { Component, Vue } from "vue-property-decorator";
import { NavigationGuard } from "vue-router";

@Component
export default class MyComponent extends Vue {
  beforeRouteUpdate:NavigationGuard = function(to, from, next) {
    next();
  }
}

In vue-router / types / router.d.ts, the type definition can be seen at the beginning of the hook function.

export type NavigationGuard<V extends Vue = Vue> = (
  to: Route,
  from: Route,
  next: (to?: RawLocation | false | ((vm: V) => any) | void) => void
) => any

Also used to previously Router, Routeall the methods, properties, and so the parameters described herein are very clear

export declare class VueRouter {
  constructor (options?: RouterOptions);

  app: Vue;
  mode: RouterMode;
  currentRoute: Route;

  beforeEach (guard: NavigationGuard): Function;
  beforeResolve (guard: NavigationGuard): Function;
  afterEach (hook: (to: Route, from: Route) => any): Function;
  push (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
  replace (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
  go (n: number): void;
  back (): void;
  forward (): void;
  getMatchedComponents (to?: RawLocation | Route): Component[];
  onReady (cb: Function, errorCb?: ErrorHandler): void;
  onError (cb: ErrorHandler): void;
  addRoutes (routes: RouteConfig[]): void;
  resolve (to: RawLocation, current?: Route, append?: boolean): {
    location: Location;
    route: Route;
    href: string;
    normalizedTo: Location;
    resolved: Route;
  };

  static install: PluginFunction<never>;
}
export interface Route {
  path: string;
  name?: string;
  hash: string;
  query: Dictionary<string | (string | null)[]>;
  params: Dictionary<string>;
  fullPath: string;
  matched: RouteRecord[];
  redirectedFrom?: string;
  meta?: any;
}

Custom-party library declaration

When not using the library tripartite declaration file with the * .d.ts, such errors will be reported when the project is compiled:

 Could not find a declaration file for module 'vuedraggable'. 'D:/typescript-vue-admin-demo/node_modules/vuedraggable/dist/vuedraggable.umd.min.js' implicitly has an 'any' type.
  Try `npm install @types/vuedraggable` if it exists or add a new declaration (.d.ts) file containing `declare module 'vuedraggable';`

Roughly meaning vuedraggable not find the declaration file, you can try to install @ types / vuedraggable (if present), or customize the new declaration file.

Installation @ types / vuedraggable

Prompted to select a first embodiment, the installation @types/vuedraggable, and then found the error 404 not found, the packet does not exist in this description. This component kinda feel people use (weekly downloads 18w), did not think the community actually did not file a statement.

Custom declaration file

But you can only choose the second way, to tell the truth and he is groping for a little time (mainly in this area did not do more to understand, are not familiar with)

First create vuedraggable folder under node_modules / @ types, if not @types folders can be created on their own. vuedraggable folder created index.d.ts. Write the following:

import Vue from 'vue'
declare class Vuedraggable extends Vue{}
export = Vuedraggable

No error recompile, solve the problem.

Recommendations and precautions

Transformation process

  • When access TypeScript, do not have to read all the files at one time ts grammar, syntax of the original can also normal operation, the best is a single modification
  • A long list of mistakes is normal, basically the type of error occurs when the initial transformation, in accordance with the error to modify the corresponding translation error
  • When introducing ts file, no need to add .tsthe suffix
  • After you define global variables for the project does not work, re-run again server (happened to me ...)

Encounter problems

  • Oriented search engine, if you know where is the problem
  • Carefully look at the document, most mistakes are more basic, the document can solve the problem
  • Github find TypeScript related projects and see how others write

Written in the last

Smoking idle time entry-wave TypeScript, try to access a back-end management system TypeScript, after all, only to know what real shortage, more records are how to use TypeScript, as well as the problems encountered in the Vue. The present work has not yet officially use to TypeScript, learning new technology requires cost and time, are some of the most medium and large companies in respected. All in all, learn more always a good thing, learning should look more training, know that the more multi-paradigm will be more open, the more problem-solving ideas.

Reference material

Guess you like

Origin www.cnblogs.com/chanwahfung/p/11968205.html