1. TS中的工程化 #

2. 编译参数 #

参数 功能
rootDir,outDir 配置输入输出目录
lib,jsx 添加基础库的能力
noImplicitAny,strict 更严格的模式
module,target,declaration,sourceMap 控制输出的内容
watch 观察模式
allowJs 允许编译javascript文件

3. 代码检查 #

3. 代码检查 #

3.1 模块安装 #

cnpm i eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

3.2 eslintrc配置文件 #

module.exports = {
    "parser":"@typescript-eslint/parser",
    "plugins":["@typescript-eslint"],
    "rules":{
        "no-var":"error",
        "no-extra-semi":"error",
        "@typescript-eslint/indent":["error",2]
    },
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
          "modules": true
        }
    }
}

3.3 npm命令 #

"scripts": {
    "start": "webpack",
    "build": "tsc",
    "eslint": "eslint src --ext .ts",
    "eslint:fix": "eslint src --ext .ts --fix"
  }

代码

var name2 = 'zhufeng';;;
if(true){
    let a = 10;
}

检查结果

src\helloworld.ts
  1:1   error  Unexpected var, use let or const instead      no-var
  1:23  error  Unnecessary semicolon                         no-extra-semi
  1:24  error  Unnecessary semicolon                         no-extra-semi
  3:1   error  Expected indentation of 2 spaces but found 4  @typescript-eslint/inden

3.4 配置自动修复 #

eslint

4. Git Hooks 检查 #

4.1 pre-commit #

4.2 安装pre-commit #

npm install pre-commit --save-dev

4.3 配置脚本 #

"scripts": {
    "build": "tsc",
    "eslint": "eslint src --ext .ts",
    "eslint:fix": "eslint src --ext .ts --fix"
  },
  "pre-commit": [
    "eslint"
  ]

如果没有在.git->hooks目录下生成pre-commit文件的话,则要手工创建node ./node_modules/pre-commit/install.js

5. 单元测试 #

5.1 安装 #

cnpm i mocha  @types/mocha chai @types/chai ts-node @types/node  --save-dev

5.2 sum.ts #

export default function sum(x:number,y:number):number{
  return x + y;
}
export default function sum(x:number,y:number){
  return (x+y).toPrecision(10);
}

5.3 sum.test.ts #

import sum from '../src/sum';
import * as assert from 'assert';
import * as chai from 'chai'
describe('test sum',()=>{
  it('1+1=2',()=>{
    assert.equal(sum(1,1),2);
  })
  it('2+2=4',()=>{
    chai.expect(2+2).to.be.equal(4);
  })
});
it('0.1+0.2=0.3',()=>{
    assert.equal(sum(.1,.2),.3);
})

5.4 断言库 #

5.4.1 assert #

5.4.2 chai #

// 相等或不相等
expect(1 + 1).to.be.equal(2);
expect(1 + 1).to.be.not.equal(3);
let a = {name:'zhufeng'};let b = {name:'zhufeng'};
expect(a).to.be.deep.equal(b);

// 布尔值为true
expect(true).to.be.ok;
expect(false).to.not.be.ok;

// 类型判断
expect('zhufeng').to.be.a('string');
expect({name:'zhufeng'}).to.be.an('object');
function Person(){}
let person = new Person();
expect(person).to.be.an.instanceof(Person);

//包含
expect([1,2,3]).to.include(2);
expect('zhufeng').to.contain('feng');
expect({ name: 'zhufeng', age: 9 }).to.include.keys('name');

// 是否为空
expect([]).to.be.empty;
expect('').to.be.empty;
expect({}).to.be.empty;

// 正则匹配
expect('zhufengnodejs@126.com').to.match(/^zhufeng/);

头部是expect方法,尾部是断言方法,比如equal、a/an、ok、match等。两者之间使用to或to.be连接

5.5 指定测试脚本文件 #

mocha spec/{a,b}.js      执行spec目录下面的a.js和b.js
mocha test/*.js     执行test目录下面的所有文件
mocha test/**/*.js   执行test目录下面任何子目录中、文件后缀名为js的测试脚本

5.6 tsconfig.json #

{
  "compilerOptions": {
    "module": "commonjs"
  }

5.7 package.json #

  "scripts": {
    "test": "set TS_NODE_COMPILER_OPTIONS={\"module\":\"commonjs\"}  && mocha --require ts-node/register --watch --watch-extensions ts test/**/*"
  },

如果"module": "es2015"的话则需要在命令行中配置module规范

5.8 配置文件mocha.opts #

--require ts-node/register 
--watch 
--watch-extensions ts
test/sum.test.ts

5.9 方法调用 #

监控函数执行 真正执行原函数 替换原有实现 提供行为描述
spy
stub
mock
npm install sinon @types/sinon -D

5.9.1 要测试的类 #

src\todo.ts

export default class Todos{
  private todos:string[]=[]
  private store:any
  constructor(store:any){
    this.store=store;
  }  
  add(todo:string){
    this.todos.push(todo);
  }
  print(){
    console.log(this.todos);
  }
  save(){
    this.store.save(this.todos);
  }
}

5.9.2 spy #

5.9.3 stub #

import * as  sinon from "sinon";
import { expect } from "chai";
import Todos from "../src/todos";
describe("测试 Todos", () => {
  it("stub", () => {
    let store = {save(){}};
    const todos = new Todos(store);
    // 用 stub 模拟 t.add 函数,stubAdd 函数被模拟为一个空函数
    const stubAdd = sinon.stub(todos, "add").callsFake(() => {});
    // 执行被模拟的 stubAdd 函数,这时候 'eat' 并没有被真正地 push
    stubAdd("eat");
    // 尝试打印,会打印出 []
    todos.print();
    // 我们期望 stubAdd 被执行了一次
    expect(stubAdd.calledOnce).to.be.true;
  });
});

5.9.4 mock #

import * as  sinon from "sinon";
import { expect } from "chai";
import Todos from "../src/todos";
describe("测试 Todos", () => {
  it("mock", () => {
    let store = {save(){}};
    const todos = new Todos(store);
    // 这时候 console 已经被 mock 完全 mock 了
    // 这里可以调用console下的任何方法,但并不会执行
    const mock = sinon.mock(console);
    // 由于 console 已经完全被 mock了,所以我们这里可以提前描述我们预期的行为
    mock.expects("log").calledOnce;
    todos.add("eat");
    todos.print();
    // 校验
    mock.verify();
  });
});

6. 为JS添加TS支持 #

6.1 sum.js #

src\sum.js

/**
 * 可以使用注释给参数添加类型
 * @param {number} x  
 * @param {number} y 
 */
export default function sum(x,y){
  return (x+y).toPrecision(10);
}

6.3 sum.test.ts #

test\sum.test.ts

import sum from '../src/sum';
import  assert from 'assert';
describe('test sum',()=>{
  it('1+2=3',()=>{
    assert.equal(sum(1,2),3);
  })
  it('0.1+0.2=0.3',()=>{
    sum(1,2);
    assert.equal(sum(0.1,0.2),0.3);
  })
});

6.3 tsconfig.json #

{
  "compilerOptions": {
+     "checkJs": true, //允许代码中使用JS
+     "checkJs": true, //可以对JS进行类型检查

7. 持续集成 #

7.1 登录并创建项目 #

7.2 .travis.yml #

language: node_js
node_js:
  - "11"
install: npm install
script:  npm test  

7.3 运行流程 #

7.3.1 运行流程 #

7.3.2 install #

7.3.3 script #

7.3.4 钩子方法 #

Travis 为上面这些阶段提供了7个钩子

before_install  安装阶段之前执行
install 安装
before_script 脚本阶段之前执行
script 脚本阶段
aftersuccess or afterfailure 脚本成功或失败
[OPTIONAL] before_deploy 布署之前
[OPTIONAL] deploy 布署
[OPTIONAL] after_deploy 布署之后
after_script  脚本阶段之后

7.4 实战 #

7.4.1 安装hexo #

$ npm install -g hexo-cli

7.4.2 生成项目 #

hexo init zfblog
cd zfblog
npm install

7.4.3 启动项目 #

hexo generate
hexo server
hexo deploy

7.4.4 布署项目 #

$ cnpm install eslint hexo-deployer-git --save
cnpm generate
cnpm deploy

_config.yml

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: git
  repo: https://github.com/zhufengnodejs/zfblog2.git
  branch: gh-pages
  message: 

https://zhufengnodejs.github.io/zfblog2

7.4.5 同步仓库 #

syncrepos

7.4.6 设置仓库环境变量 #

变量名 含义
USERNAME git用户名 zhufengnodejs
UESREMAIL git用户邮箱 zhufengnodejs@126.com
GH_TOKEN 用户生成的令牌
GH_REF 仓库地址 github.com/zhufengnodejs/zfblog3.git
GH_BRANCH 推送的pages分支 gh-pages

2.settings

7.4.7 Github生成访问令牌 (即添加授权) #

7.4.8 .travis.yml #

language: node_js
node_js: 
    - '11'
install:
  - npm install
script:
  - hexo g
after_script:
  - cd ./public
  - git init
  - git config user.name "${USERNAME}"
  - git config user.email "${UESREMAIL}"
  - git add -A
  - git commit -m "Update documents"
  - git push --force  "https://${GH_TOKEN}@${GH_REF}" "master:${GH_BRANCH}"
branches:
  only:
    - master