乐趣区

关于typescript:使用TypeScript校验运行时数据

背景

对于前端程序猿,常见的开发流程是:

  1. 前后端约定接口
  2. 后端给出接口文档
  3. 依据接口编写 TypeScript 类型定义
  4. 开发实现进行联调

尽管一切顺利,然而上线后还是翻车了,js 报错:cannot read the property 'xx' of null,很显然前端没有解决空值,接锅吧 TT。但回头一看接口文档,跟后端同学约定的返回对象,但理论返了 null,这锅不能一个人背。那么怎样才能尽早发现这种问题呢?一种解决方案是:

  1. 将 TypeScript 类型定义转为 JSON Schema
  2. 利用 JSON Schema 校验数据正确性

针对以上计划做了一个 demo。

JSON Schema

JSON Schema 是一个 JSON 对象,用来形容和校验 JSON 对象的格局。比方上面这个 JSON Schema:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "number"},
    "hobby": {
      "type": "array",
      "items": {"type": "string"}
    }
  },
  "required": [
    "age",
    "hobby",
    "name"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#",
}

它形容了这样一个 JSON 对象:

  • 类型 – typeobeject
  • 有四个属性 – properties

    • name:类型为 string
    • age:类型为 number
    • hobby:类型为 Array<string>
  • 属性是否必须 – requirednameagehobby 都为必须

上面这个 JSON 对象就是满足这个 JSON Schema 的:

{
  "name": "Tom",
  "age": 1,
  "hobby": ["coding"]
}

能够看出 JSON Schema 还是很好了解的,但其形容语法还是有肯定学习老本,这里强烈推荐通过 jsonschema 库的 example 去学习相干语法,另外也能够看 Understanding JSON Schema。

有了 JSON Schema,怎么应用它校验 JSON 对象的合法性呢?这里就用到了刚刚提到的 jsonschema 库。简略应用示例如下:

var Validator = require('jsonschema').Validator;
var v = new Validator();
var instance = 4;
var schema = {"type": "number"};
console.log(v.validate(instance, schema));

当初能够依据 JSON Schema 去校验后端返回数据的格局是否正确了,然而为每个接口手动编写 JSON Schema 是不事实的,咱们天然会想到能不能将 TypeScript 的接口类型定义转为 JSON Schema?

TypeScript Interface -> JSON Schema

好在曾经有 typescript-json-schema 这个库帮咱们解决了这个问题,上面给出简略的应用示例:

import path from "path";
import * as TJS from "typescript-json-schema";

const settings: TJS.PartialArgs = {required: true};

// optionally pass ts compiler options
const compilerOptions: TJS.CompilerOptions = {strictNullChecks: true};

// 解析接口定义文件:index.ts
const program = TJS.getProgramFromFiles([path.join(__dirname, './apis/index.ts')],
  compilerOptions,
);

// 将 "IApi1" 这个 interface 转为 schema,传入 "*" 将转换全副 interface
let schema = TJS.generateSchema(program, "IApi1", settings) || {};

一顿操作后就能够将上面这个 interface 转为文章结尾给出的示例 JSON Schema:

interface IApi1 {
  name: string;
  age: number;
  hobby: string[];}

而后再用 node 将刚刚失去的 schema 存成 json 文件:

fs.writeFileSync(path.join(__dirname, "./json-schema", "schema.json"), schema); 

接着就能够应用相应的 JSON Schema 对后端数据进行校验了:

import {Validator} from 'jsonschema'

const apiSchema = require('./json-schema/schema.json')
const v = new Validator();
Api1().then(res => {const validateRes1 = v.validate(res, apiSchema)
  console.log(validateRes1);
});

残缺的示例能够看:demo

在工程中的实际

1、如何组织散落的接口类型定义?
我集体比拟喜爱的形式是:在 apis.ts 文件中对立去写所有的接口定义和类型定义,这样在转换 JSON Schema 时去解决这一个文件即可。

2、怎么主动将类型定义转为 JSON Schema?
应用 husky,在 pre-commit 阶段去执行转换工作,进一步能够应用 lint-staged 判断以后提交是否波及到接口定义文件的改变,有改变再执行转换。

3、何时校验数据?
这里我想到两个场景:

  • 生产上:对于一些要害接口,在接口返回数据后调用校验逻辑,如果校验有错,须要做两件事:第一是将谬误数据转为正确的备用数据,以防页面挂掉;第二是上报谬误;
  • 测试时:写各种测试用例去测后端接口,校验返回数据的正确性,这样就不必人眼去校验数据是否正确了。
退出移动版