TypeScript 使用心得

zehuiguan

认识 TypeScript

TypeScript 的定位、特点

背景

TypeScript是一种由微软开发的自由和开源的编程语言。本质上是向 JavaScript 增加静态类型系统,是JS的超集,为大型软件开发而设计的,它最终编译产生 JavaScript,所以可以运行在浏览器、Node.js环境。

静态类型

静态类型指的是编译器在compile time执行类型检查,动态类型指的是在runtime执行类型检查。

 

简单地说,在声明了一个变量之后,不能改变它的类型的语言,是静态语言;能够随时改变它的类型的语言,是动态语言。

有人说,使用ESLint就可以对JavaScript进行代码检查,可以不需要TypeScript

不完全正确

区别一

ESlint 检查的是代码规范,是团队协作时风格代码的规范工具。

区别二

虽然两者都有对程序进行分析的能力,但ESLint是无法进行静态分析。除了校验语法是否出错外,关于逻辑错误(如函数返回值混淆等)是没法校验的。

原文: Code linting is a type of static analysis that is frequently used to find problematic patterns or code that doesn’t adhere to certain style guidelines.  

TS 和 JS 的关系

  • JS的超集,向下兼容JavaScript
  • 增加类型标记的语法,以实现静态分析
  • TS也能做ES新语法编译老语法的功能,跟Babel一样(但弱于babel)

TypeScript的好处

探测错误

静态类型的首要优势是early fail,即你编写的代码即使没有被执行到,一旦你编写代码时发生类型不匹配,在编译阶段即可发现。
// 根据时间推算问候语

function getGreetMsg(time) {
    if (time < 10) {
        return "Good morning";
    }
    else if (time < 18) {
        return "Good day";
    }
}

const msg = getGreetMsg(22).split('');

一段跑飞的代码

脆弱的JS

使用tsc进行编译,甚至无需添加类型标注。结果编译报错

重构辅助工具

通用函数修改了入参,TS会静态分析所有参数不匹配的地方,然而JS会忽略,甚至不报错

// 根据时间推算问候语

interface GetGreesMsg {
    (date: string, time: number): string;
}

let getGreetMsg: GetGreesMsg;

getGreetMsg = function (date, time) {
    if (time < 10) {
        return `Today is ${date}, Good morning`;
    }
    else if (time < 18) {
        return `Today is ${date}, Good day`;
    } else {
        return `Today is ${date}, Good evening`;
    }
}

const msg1 = getGreetMsg('2017-12-12', 22).split(''); //正确传输参数
const msg2 = getGreetMsg(22).split(''); //缺了参数

这里函数有一处调用缺少一个参数,但JS打包并不会报错

TS会检查入口参数的类型,检测所有调用函数的地方

抽象

基于TS的Interface,可以强化规范编程,用带清晰接口的模块来结构化大型系统,让设计脱离实现,最终体现出一种接口定义语言的优势。同时也增强代码的可阅读性。
let cachedInfo = JSON.parse(Session.get('userInfo')) || {}

export interface AccountNoList {
    accountNo?: string;
    userId?: string;
    [index: string]: any;
}[]

export interface State {
    list: AccountNoList;
    role: string;
    phoneNo: string
}

export interface Mutations {
    [Type.UPDATE_USER_INFO](state: State, ret: State): void;
    [Type.UPDATE_USER_PHONENO](state: State, phoneNo: string): void;
}

企业微信H5中的vuex例子——定义state,mutation接口


const mutations: Mutation = {
    [Type.UPDATE_USER_INFO](state, ret) {
        state.role = ret.role;
        state.list = ret.list;
    },

    [Type.UPDATE_USER_PHONENO](state, phoneNo) {
        state.phoneNo = phoneNo;
    },
}

最终实现上述interface

type Fell = 'good' | 'bad';
interface Eatable {
  calorie: number;
  looks(): Fell;
  taste(): Fell;
  flavour(): Fell;
}

简单地定义了一个Implements

class Durian implements Eatable {
  calorie = 1000;
  looks(): Fell {
    return 'good';
  }
  taste(): Fell {
    return 'good';
  }
//  flavour(): Fell {
//    return 'bad';
//  }
}

实现了榴莲的class,但是把flavour实现干掉了

提示flavour没有实现

TS+VUE的开发模式

Evan You谈Vue2.5加大对TS的支持

  • Vue 从 2.0 开始就已经有官方的类型声明文件了(包括vuex, vue-router),但是在TS下,Vue 缺乏开箱即用的API,无法自动推论出 this 的类型(需要借助 vue-class-component,即使用class模式的写法)
  • vue2.5+ 将增强对API、Props中this的类型推论
  • 即便不用TS,在 VSCode 中使用 Vetur 插件即可获得自动补全和类型提示功能
  • 升级TS的一些准备工作
  • vue-cli 即将支持新建 vue+TS 工程

选择依赖

  • typescript:必须项

  • ts-loader:必须项

  • vue-class-component:官方维护,解决类型推断出错问题,提供component装饰器

  • vue-property-decorator:继承vue-class-component,增强了更多的结合 Vue 特性的装饰器

  • vuex-class:继承vue-class-component , 提供了Vuex 的绑定的装饰器

tsconfig.json

{
  "compilerOptions": {
    //严格模式
    "strict": true,
    // 以esnext的版本去处理TS中新ES的语法
    "module": "esnext",
    // 支持require形式引进模块
    "moduleResolution": "node",
    // 编译输出目标 ES 版本
    "target": "es5",
    // 允许编译javascript文件,在从JS升级到TS过程中很有帮助
    "allowJs": true,
    // 官方推荐,允许从没有设置默认导出的模块中默认导入,
    // 即ES-style imports(import Vue from ‘vue’)
    "allowSyntheticDefaultImports": true,
    // 官方推荐,vue-class-componet等,启动装饰器
    "experimentalDecorators": true,
    // 编译过程中需要引入的库文件的列表
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

webpack配置

  • entry入口文件 app.js 改为 app.ts
  • module.rules添加 .ts 解析规则
  • resolve.extensions添加 .ts  
  • 配合mumble-next使用,打包编译依然使用babel转换语法、编译API(tsc并不能保证编译新语法)

围绕vue-class-component的生态圈

TS缺点

  • 声明文件不完善
  • 有限支持ES的新特性,只支持到stage-3
  • 适合大型、多人合作项目,小型项目(简单调用API、简单填空框架)耗时长、繁琐
  • 在声明文件的作用下,使用vscode的vetur编码JS会有代码提示、自动补全功能,小型项目写ts略显多余