Vue2 + TypeScript实践准备 
基于Vue2.5版本,Vue3.0可能有所改变.
 
知识准备 
Node.js Node.js是什么? 
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式I/O 的模型,使其轻量又高效。
 
npm模块管理器 npm有两层含义。一层含义是Node的开放式模块登记和管理系统,网址为npmjs.org 。另一层含义是Node默认的模块管理器,是一个命令行下的软件,用来安装和管理Node模块。
1 2 3 4 5 6 7 npm init npm install lodash-es npm uninstall lodash-es npm update lodash-es npm install lodash-es --save npm install lodash-es --save-dev 
 
npm run 
npm不仅可以用于模块管理,还可以用于执行脚本。package.json文件有一个scripts字段,可以用于指定脚本命令,供npm直接调用。
 
1 2 3 4 5 6 7 8 9 {     "scripts" : {         "serve" : "vue-cli-service serve" ,         "build" : "vue-cli-service build" ,         "lint" : "vue-cli-service lint" ,         "test:unit" : "vue-cli-service test:unit"      } } 
 
 
package.json文件 
每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
 
name:描述的是模块的名称
 
version: 描述模块的版本号(遵循语义化版本)
 
main: 指定入口文件,默认为index.js
 
dependencies:字段指定了项目运行所依赖的模块
 
devDependencies:指定项目开发所需要的模块。
 
scripts: npm run 执行的命令就是这里指定的。 
 
CommonJS规范 
Node 应用由模块组成,采用 CommonJS 模块规范。
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
 
1 2 3 4 5 6 7 8 9 var  x = 5 ;var  addX = function  (value )  {  return  value + x; }; module .exports.x = x;module .exports.addX = addX;
 
1 2 3 4 5 var  example = require ('./example.js' );console .log(example.x); console .log(example.addX(1 )); 
 
TypeScript 
TypeScript具有类型系统,且是JavaScript的超集。 它可以编译成普通的JavaScript代码。 TypeScript支持任意浏览器,任意环境,任意系统并且是开源的。
 
基础类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 let  isDone: boolean = false ;let  decLiteral: number = 6 ;let  hexLiteral: number = 0xf00d ;let  binaryLiteral: number = 0b1010 ;let  octalLiteral: number = 0o744 ;let  name: string = "bob" ;let  list: number[] = [1 , 2 , 3 ];let  list: Array <number> = [1 , 2 , 3 ];let  x: [string, number] = ['hello' , 10 ]; x[3 ] = 'world' ;  enum Color {     Red,      Green,      Blue } let  c: Color = Color.Green;
 
任意值any 
但是 Object 类型的变量只是允许你给它赋任意值 - 但是却不能够在 它上面调用任意的方法 .
 
1 2 3 4 5 6 7 8 let  notSure: any = 4 ;notSure.ifItExists();  notSure.toFixed();  let  prettySure: Object  = 4 ;prettySure.toFixed();  
 
空值void 
void 类型像是与 any 类型相反,它表示没有任何类型 
 
1 2 3 4 5 6 function  warnUser ( ): void   {	alert("This is my warning message" ); } let  unusable: void  = undefined ;
 
null和undefined 
默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以 把 null 和 undefined 赋值给 number 类型的变量。 
 
1 2 let  u: undefined  = undefined ;let  n: null  = null ;
 
注意:当你指定了 –strictNullChecks 标记, null 和 undefined 只能赋值给 void 和它们各自。 
 
Object 
object 表示非原始类型,也就是除 number , string , boolean , symbol , null 或 undefined 之外的类型。 
 
强制类型转换 1 2 3 4 let  someValue: any = "this is a string" ;let  strLength: number = (<string > someValue).length;// as 语法 let strLength: number = (someValue as string).length; 
 
可选属性 
可选属性使用? 标识
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 export  interface  ComponentOptions<  V extends  Vue,   Data=DefaultData<V>,   Methods=DefaultMethods<V>,   Computed=DefaultComputed,   PropsDef=PropsDefinition<DefaultProps>,   Props=DefaultProps> {   data?: Data;   props?: PropsDef;   propsData?: object;   computed?: Accessors<Computed>;   methods?: Methods;   watch?: Record<string , WatchOptionsWithHandler<any > | WatchHandler<any > | string >;        } 
 
去除null和undefined类型断言使用! 标识 
有的时候TypeScript无法正确推导出类型时,需要手动去除null和undefined
 
1 2 3 4 5 export  default  class  Login extends  Vue {    @Mutation (UserMutationTypes.SET_USER_NAME)     private  changeUserName!: (name: string  ) =>  void ;      } 
 
接口 
在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。 
 
1 2 3 4 5 6 7 8 9 interface  LabelledValue {  label: string ; } function  printLabel (labelledObj: LabelledValue )  {	console .log(labelledObj.label); } let  myObj = {size: 10 , label: "Size 10 Object" };printLabel(myObj); 
 
类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Animal {    move(distanceInMeters: number  = 0 ) {     	console .log(`Animal moved ${distanceInMeters} m.` );     } }  class  Dog extends  Animal {    bark() {     	console .log('Woof! Woof!' );     } }  const  dog = new  Dog();dog.bark(); dog.move(10 ); dog.bark(); 
 
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  add (x, y )  {	return  x + y; } let  myAdd = function (x, y )  {     return  x + y;  }; function  tsAdd (x: number , y: number  ): number   {	return  x + y; }  let  tsMyAdd = function (x: number , y: number  ): number   {     return  x +y;  }; 
 
声明合并 
注意每组接口里的声明顺序保持不变,但各组接口之间的顺序是后来的接口重载出 现在靠前位置。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface  Cloner {	clone(animal: Animal): Animal; } interface  Cloner {	clone(animal: Sheep): Sheep; } interface  Cloner {    clone(animal: Dog): Dog;     clone(animal: Cat): Cat; } interface  Cloner {    clone(animal: Dog): Dog;     clone(animal: Cat): Cat;     clone(animal: Sheep): Sheep;     clone(animal: Animal): Animal; } 
 
扩充全局或者模块作用域 
不论是模块扩充还是全局声明扩充都不能向顶级作用域添加新的项目 - 它们只能为 已经存在的声明添加 “补丁”.
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import  { Observable } from  "./observable" ;declare  module  "./observable" {	     interface  Observable<T> {     	map<U>(proj: (el: T ) => U ): Observable <U >;      } } Observable .prototype .map  = /*...*/;// declare  global  声明被增强: declare  global  {    interface  Array <T > {     	mapToNumbers () : number [];     } } Array .prototype .mapToNumbers  = function  ()  { /* ... */ }
 
Vue对TypeScript的支持 
Vue的TypeScript 支持 
 
TypeScript识别Vue组件 1 2 3 4 5 declare  module  "*.vue" {  import  Vue from  "vue" ;   export  default  Vue; } 
 
TypeScript识别JSX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Vue.component('anchored-heading' , {   render: function  (createElement )  {     return  createElement(       'h'  + this .level,          this .$slots.default      )   },   props: {     level: {       type : Number ,       required: true      }   } }); declare  global {  namespace  JSX {          interface  Element extends  VNode {}          interface  ElementClass extends  Vue {}     interface  IntrinsicElements {       [elem: string ]: any ;     }   } } 
 
扩展Vue类和原型声明书写 1 2 3 4 5 6 7 8 9 declare  module  'vue/types/vue' {  interface  Vue {     $axios: AxiosInstance   }   interface  VueConstructor {     $axios: AxiosInstance   } } 
 
Vue组件声明方式1 1 2 3 4 5 6 7 <template >     <div >          <div  class ="greeting" > Hello {{name}}{{exclamationMarks}}</div >          <button  @click ="decrement" > -</button >          <button  @click ="increment" > +</button >      </div >  </template > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 </script><script lang="ts">  import Vue from "vue"; export default Vue.extend({     props: ['name', 'initialEnthusiasm'],     data() {         return {             enthusiasm: this.initialEnthusiasm,         }     },     methods: {         increment() { this.enthusiasm++; },         decrement() {             if (this.enthusiasm > 1) {                 this.enthusiasm--;             }         },     },     computed: {         exclamationMarks(): string {             return Array(this.enthusiasm + 1).join('!');         }     } }); </ script>
 
1 2 3 4 5 <style > .greeting  {    font-size : 20px ; } </style> 
 
Vue组件声明方式2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import  Vue from  'vue' import  Component from  'vue-class-component' @Component({      template: '<button @click="onClick">Click!</button>'  }) export  default  class  MyComponent  extends  Vue   {     message: string = 'Hello!'       onClick (): void  {     window .alert(this .message)   } } 
 
Vue组件使用注意事项 
vue-class-component注解的限制 
methods直接声明为类方法成员 .
 
计算属性 声明为类属性访问器 .
 
data声明为类的字段。
 
data , render和所有的Vue生命周期钩子函数都能可以直接声明为类成员方法。但是你不能在Vue实例上直接调用。当你声明自定义方法时,应该避免声明周期钩子函数保留的名字
 
其它的options属性,使用传递给@Component装饰器函数。例如:components属性
 
 
data属性声明注意事项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Component export  default  class  Login extends  Vue {    public  name: string  = 'login' ;          private  userName: string  = '' ;     private  userPass: string  = '' ;     @Mutation (UserMutationTypes.SET_USER_NAME)     private  changeUserName!: (name: string  ) =>  void ; 	          data() {         return  {             labelPosition: 'right' ,         };     } } 
 
如果data属性需要在class的method中修改时,声明为类的字段。
如果data属性只在template中使用,可以使用data函数返回.
 
TypeScript官方声明文件仓库 
引入第三方库(没有声明文件) 
比如说我想引入async-validator,虽然已经在本地安装,但是typescript还是提示找不到模块。原因是typescript是从node_modules/@types目录下去找模块声明,有些库并没有提供typescript的声明文件,所以就需要自己去添加
解决办法:在src/types目前下建一个async-validation.d.ts文件,声明这个模块即可
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 declare  module  'async-validator' {    export  type  AsyncValidator<T = object> = (       rule: RuleConfig,       value: any ,       callback: ValidatorCallback,       source: T,       options: {         messages: object;       },     ) => void ; } declare  module  '*.vue' {  import  Vue from  'vue' ;   export  default  Vue; } 
 
前端涉及的知识 前端基础 
JavaScript / HTML / CSS
 
ES6 的使用
 
 
Vue部分 
Node部分 
Node.js模块知识 
CommonJs规范(require, module, export) 
npm基本使用 
Node.js的package.json和模块知识 
 
Webpack 
了解Webpack配置
 
Webpack插件
css-loader, style-loader, sass-node…
 
 
 
TypeScript 
TypeScript基本语法 
TypeScript类型声明文件*.d.ts写法 
tsconfig.json文件配置 
了解tslint.json 
 
其它类库 
链接 npm模块管理器 
npm 模块安装机制简介 
vue-cli:
https://cli.vuejs.org/zh/ 
vue-router: 
https://router.vuejs.org/zh/ 
vuex:
https://vuex.vuejs.org/zh/guide/ 
vue-loader:
https://vue-loader.vuejs.org/zh/spec.html 
vue-class-component
https://github.com/vuejs/vue-class-component 
vue-property-decorator
https://github.com/kaorun343/vue-property-decorator 
vuex-class
https://github.com/ktsn/vuex-class/ 
Axios.js
https://github.com/axios/axios 
Vue的TypeScript支持
https://cn.vuejs.org/v2/guide/typescript.html 
语义化版本
https://semver.org/lang/zh-CN/ 
TypeScript+ Vue起步
https://github.com/Microsoft/TypeScript-Vue-Starter#typescript-vue-starter 
https://github.com/SimonZhangITer/vue-typescript-dpapp-demo 
vue + typescript 项目起手式
https://segmentfault.com/a/1190000011744210 
https://segmentfault.com/a/1190000011878086 
https://github.com/ws456999/vue-typescript-starter 
https://www.zhihu.com/question/310485097