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