seho 发布的文章

前言

我们在开发中可能会经常遇到以下几个事情:

  1. api接口文档描述不清
  2. 没有mock流程
  3. 如果使用ts开发,需要手动的描述类型,而且在前端中较难把api类型复用

社区中有大量的api文档工具,支持mock,单测的数不胜数。但是有生态,而且有开放api的开源文档工具其实寥寥无几。yapi是开源的国产文档管理工具,我们可以用yapi的开放api去做一系列拓展,在市面上就有许多浏览器插件/vscode插件,而且它支持私有部署。我们今天就使用我们之前文档提到过的工程架构模板,去构建一个todolist应用,我们的api则是使用midway和serverless快速开发的。

如果你还不太了解我们之前使用的“工程架构模板”,那你可以看一下这篇文章

YAPI

准备了4个api供我们测试,它们都是隶属于List模块,api的源码在这里,我们需要在yapi平台上把这些api进行登记。
我们新建了一个测试项目,并且新建了一个list分类,同时新增了4个api:

1. /v1/list get
2. /v1/list post
3. /v1/list delete
4. /v1/list put

WX20211021-213731.png

我们list模块类型声明如下:

export interface List {
  id: string;
  title: string;
  content: string;
}

export type AddItem = Omit<List, 'id'>;
export type UpdateItem = List;

比如说新增的api,在post方法下,我们需要传递title,content,返回一个新增成功的id,这是一个很常见的业务场景,我们在yapi定义一下。

1634827748418.jpg

这个时候就需要体现出社区的强大了,在社区中有类似yapi2typescript的浏览器插件,所以我就fork一份,再插件之上重新修改了interface名等&新增了controller,modle层代码片段,如果你需要安装这个插件,你可以到这个仓库查看源码

我们就可以在页面下面看到,如下的类型提示:

WX20211025-170349.png

然后我们就可以copy到我们的工程中进行使用,这个时候你可能会问,yapi社区里有很多to typescript的方案,比如说vscode或者命令行工具,为什么要使用浏览器插件?出于以下几点原因,我使用浏览器插件:

  1. 不依赖IDE,让团队能更好的统一
  2. 不过度依赖yapi,大多数生成方案强绑定yapi,通过api去和本地type diff,这样不容易去单独修改type,难以和临时变化的api协调。

我们通过vscode命令model-init-type 去生成一个list.d.ts文件内容, 然后把yapi的类型提示进行粘贴:

namespace TListApiModel {
  interface ReqAddList {
    /** 列表标题 */
    title: string;
    /** 列表内容 */
    content: string;
  }

  interface ResAddList {
    /** 数据id */
    id: string;
  }
}

export default TListApiModel;

然后我们就使用命令快速实现一下,list模块的model层和controller层:

// model api
import useRequest from '../../hook/useRequest';
import TListApiModel from '../../../typings/model/api/list';
export default class ListApiModel {
  addList(params: TListApiModel.ReqAddList): Promise<TListApiModel.ResAddList> {
    return useRequest({
      url: '/v1/list',
      method: 'POST',
      data: params
    });
  }
}
// controller
import TListApiModel from '../../typings/model/api/list';
import ListApiModel from '../model/api/list';
export default class ListController {
  private apiModel: ListApiModel;
  constructor() {
    this.apiModel = new ListApiModel();
  }
  addList(params: TListApiModel.ReqAddList) {
    return this.apiModel.addList(params);
  }
}

测试

enjoy模板新增了jest,我们可以直接使用jest对功能进行测试,如下:

// tests/model/api/list.test.ts

import ListController from '../../../src/controller/list';

describe('addList', () => {
  const controller = new ListController();
  it('添加参数测试-1', async () => {
    await controller.addList({
      title: 'test',
      content: 'nihao'
    });
  });
  it('添加参数测试-2', async () => {
    const result = await controller.addList({
      title: 'test2',
      content: 'hello?'
    });
    console.log(result.id);
  });
});

运行npm run test tests/model/api/list.test.ts

WX20211025-172728.png

文章源代码预览

前言

不知不觉剑指题解即将陪伴大家走过了一年时间,事实上从项目开始萌生想法和方向是2020年的10月中旬,在今年的三月份才开始大量产出代码。我利用自己每天的空余时间去设计,去运营,去开发自己的东西,我把所学所感都会输出在这个项目。结果很不错我在今年的6月份拿到了Dcloud三等奖,并且坚守诺言,开源了每一句代码以及每一个设计素材,这里要非常感谢@谢敏和@马瑞朝对项目的大力支持。没有谢敏同学就没有APP丰富好看的ui界面,她在很多地方都加入了代码色彩非常贴近用户,所以她设计出来的成品是非常好的,开源之后很多人都借鉴或者复用了谢敏同学的设计,这也是对谢敏大大的认可。在题解项目前期主要是马瑞朝同学给我疏通逻辑,去参与系统设计,让我一个以前端为主的假全栈能够得心应手的去玩转serverless以及文档数据库。在10月份会迎来一次全新的 "release版本: v1.1.0",这篇文章将会简单说一下v1.1.0我们新增了哪些东西~

版本说明v1.1.0

【npm包】新增typescript-type核心包,重构了unicloud/explain/sword-core等所有类型提示
【后端】unicloud后端架构大幅调整,从explain1->explain2,所有核心云函数都将采用http云函数URL化
【后端】后端架构调整&代码重构&美化代码
【后端】新增TS运行时校验功能
【后端】后端核心函数新增中间件体系
【后端】更改explain2核心部分代码
【后端】核心主要函数将cjs替换为es
【生态】QQ机器人系统,推送海量题目
【生态】微信小程序结束了审核,此后微信小程序&QQ小程序将会正常迭代
【前端】重构&美化了API层的所有代码(*下一个版本会重点改进这里)
【官网】更改官网的部分内容
【依赖】app核心工程升级了所有的依赖包到最新版本(*后续会对windows电脑部署项目出现的bug进行修复)
【app】整个app工程引入了husky和lint-staged,eslint

架构调整

请输入图片描述

代码重构&美化

控制器改造之前:

WX20211006-144636.png

控制器改造之后:

WX20211006-144603.png

TS运行时校验

1633503145303.jpg

QQ机器人

WX20211006-145431.png

新增全局类型npm包

github: sword-typescript-type-core
npm: sword-typescript-type-core

WX20211006-145610.png

补丁包&v1.1.0 next版本预告

【前端】API类型提示
【前端】部分页面代码进行美化&重构
【前端】全方位优化用户体验
【生态】服务号推送&通知(微信端)
【生态】QQ群合作
【生态】题库完善,增加java&php的题库
【后端】完善其他云函数(*openapi)

vue3-vite2-ts-template

托管地址: github-vue3-vite2-ts-template

  • [x] 使用最新版本的 vite 和 vue3
  • [x] antdv 真正意义上的按需加载组件以及组件css
  • [x] git 提交前的 lint-stage+husky 校验和美化代码(prettier), 多人协作风格统一
  • [x] 开发预设 eslint 校验和自动修复以及 Editorconfig
  • [x] 自带开发常用依赖,antdv, axios, day, querystring...
  • [x] 适合中小项目的 typescipt 的 mvc 风格架构
  • [x] 工具方法贯彻 hook 风格,且预装 vueuse
  • [x] scss 基本工具库封装,页面和页面无需引入,直接使用预定义的全局变量/函数
  • [x] vite/rollup 打包优化
  • [x] storage,cookie TS版本的模块化方案
  • [x] 预设 Pinia 状态管理的模块化以及类型声明
  • [x] 预设开发环境的 vite-plugin-mock
  • [x] 预设自动装载路由 vite-plugin-pages
  • [ ] SSR/CSR 优化
  • [ ] 业务组件/type 类型文档自动生成,且在启动开发服务器时,自动打开 doc
  • [ ] 动画方案
  • [ ] 预装业务常用的 webcomponents 组件(团队自己开发组件库)

命令

命令含义
dev快速启动本地开发服务器
lint带有--fix 的 eslint 校验
prettiereslint-prettier 的美化代码命令
preparenpm install 自动执行的 husky 安装命令(不使用的请忽略)
lint-stage对 git 暂存区的文件进行操作,源于 lint-stage 插件
buildvite 内置的打包使用 rollup,此模板自带打包优化
serve本地预览生产环境的程序

启动/打包 命令

命令含义
dev:test快速启动本地开发服务器(test 环境)
dev:prod快速启动本地开发服务器(prod 环境)
build:test打包(test 环境)
build:prod打包(prod 环境)

技术栈:

  1. vue3
  2. vueRouter4
  3. pinia
  4. typescript

命令行

通过安装Tool,来可视化地使用模板,因为仓库中的模板大多数都不会全部用到,你可以通过tool去按需引入它们

npm i enjoy-project-tool -g

创建模板

enjoy create

当然,作为模板的伴生工具,我还会继续维护并且持续提出新的feature来减轻我们开发负担

Tool是使用TS开发的,如果你感兴趣可以提pr,这是Tool的仓库

类型文档/组件文档

文档待补充,暂定使用

  1. dumi作为组件库文档

代码提交

旧版本的husky和新版还是有很多不一样的,所以如果你以前用过husky那么你要在代码提交这里做更多逻辑的话,可以去看看最新的文档。

模板中只拦截了pre_commit这个钩子,目标就是在pre_commit的时候对代码进行lint和自动修复以及美化,而且仅要对暂存区的文件lint,所以使用了lint-staged。这个组合太常见了,有需求的开发者可以再这个上层定义一些有趣的功能提pr。

还有一个需求是校验git commit message的规范,但是对于小团队来讲,校验这个规范没有太大必要,也暂时不会对团队带来好处,所以爱鼓捣的可以去鼓捣哈。

可以推荐团队成员使用 git-commit-plugin-vscode

vscode 开发小指南

推荐使用 Volar 插件进行开发,如果你的 IDE 是 Jetbrains 系列的,那么你可能不太需要这个插件,如果你是 vscode 推荐使用 volar。使用 volar,不仅可以在 vue 开发上和
jetbrains 的表现一致,还可以得到更完善 vue3 的支持,甚至非常新/在草案的语法糖都能够快速享受到。

下载volar地址

此模板对于vscode有天然的支持,如果你使用vscode,就能使用模板自带的vscode配置,比如说保存自动lint&fix&prettier或者其他有意思的功能。

  1. 有那么一点智能的代码模板

模板中自带了若干个vscode的code-snippets,snippets将会持续更新,它和模板深度贴合,可以帮助你摆脱繁琐的开发。下面就一一描述几个snippets的作用:

  • model-init-type

    初始化@types/model/api的提示工具,自动声明命名空间以及导出

  • model-init-api

    初始化model下的api类,自动引入与之匹配的type类型声明文件以及其他可能用到的依赖

  • model-init-cache

    初始化model下的cache类,自动引入与之匹配的type类型声明文件以及其他可能用到的依赖

  • controller-init
初始化控制器类

  • vue-init

    初始化vue页面/组件

AntdV 开发小指南

传统的 antdv 的按需加载,都会使用 babel-plugin-import 这个插件进行按需分析然后自动引入,但是 antdv 中有很多嵌套的父子组件:

<a-menu>
  <a-menu-item></a-menu-item>
</a-menu>

由于内部设计原因,无法使用这个插件进行按需导入。最主要的是我们已经使用了vite,本身就带有按需导入,我们只需要处理他们的css的按需引入即可。所以使用了2个插件:

  1. vite-plugin-components
  2. vite-plugin-style-import

第一个插件主要帮助我们自动识别模板中用到的组件,实现自动引入,也就是说我们使用antdv这样的组件库的时候,不需要全量引入,甚至不需要手动的import就可以自动实现按需引入,如图:

而且脚手架内置了按需引入css的逻辑,所以antdv本身的设计原因导致引入css问题开发者也不需要担心。
第二个插件主要是辅助第一个插件做按需引入css逻辑的。第一个插件做的按需引入css有些许问题,比如说antdv里面有很多api调用的组件,比如message,通过message方法调用一个组件,这个时候css不生效,就需要使用第二个插件进行处理。

对于message这样的api组件的css不生效的原因很简单,第一个插件仅仅是解析template用到的组件然后自动引入css,但是无法处理import进来的api组件,所以需要第二个插件做处理。

开发指南

这一块根据自身团队成员的习惯会逐步调整,所以这里的介绍会经常更改。

这套微不足道的架构足以应对中小APP,也是非常简单的,主要就是mvc+ts风格。如果你阅读完整个模板文档之后,你会发现很多东西都做了模块化,把业务划分开了,这也是目前团队开发没有注意到的一点,自身开发完爽是爽了,另外一个人维护就要惨了。各种配置,api都找不到,组件/组件参数也找不到,可能为了快速开发,都会去复制老项目和其他页面的代码;这虽然也是一种“复用”,但是总归来说并不是标准的。所以只有将业务划分开,才能快速定位具体核心代码,才能快速复用。

类型

src/@types

像大部分工程一样,把能抽离的type都尽量都抽离到了@types这一层,这一层也暂时根据需求划分了以下几个内容:

  1. controller
  2. model
  3. hook
  4. store

里面最重度使用的应该是model,我们在model模型中根据业务定义了很多ts,比如user.ts:

namespace TUserApiModel {
  type ReqLogin = {
    captcha: string;
    password: string;
    username: string;
    uuid: string;
  };

  type ResLogin = Promise<
    ActionResult<{
      token: string;
    }>
  >;
}

export default TUserApiModel;

这两个就代表了model里面api层(后面会详细说明model里面的api),使用Req和Res作为前缀也就是请求和响应的类型,那么我们定义好之后,在整个工程中我就可以这样使用类型:

TUserModel.ReqLogin

那么同理,types文件夹中像store,hook这样的,也是根据业务划分,去定义类型的,这里就不再过多阐述了。

模型

src/model

目前model分为2个含义:

  1. api
  2. cache

前端大部分的数据来源都包含到了,api模型定义了不同业务的api方法,比如user.ts:

import useRequest from '../../hook/useRequest';

export default class UserApiModel {
  async login(params: TUserModel.ReqLogin): TUserModel.ResLogin {
    return await useRequest({
      url: `${params}`,
      method: 'get',
      options: {
        authApi: true
      }
    });
  }
}

useRequest是我们自定义实现的hook函数,我们通过这个hook可以发起请求,那么你可以看到在这个类中定义了login这个方法,入参类型就是TUserModel.ReqLogin, 返回类型就是TUserModel.ResLogin,这个类型都是我们在@types定义的。

再比如说我们搭配kurimudb做了缓存的模块化,最常用的缓存插件也预装好了,我们可以在model里面去写这样一段代码:

/model/cache/user.ts

import { Models } from 'kurimudb';
import { LocalStorageDriver } from 'kurimudb-driver-localstorage';
import { CookieDriver } from 'kurimudb-driver-cookie';

export class UserLocalStorage extends Models.keyValue {
  constructor() {
    super({
      name: 'user',
      driver: LocalStorageDriver
    });
  }
}

export class UserCookie extends Models.keyValue {
  constructor() {
    super({
      name: 'user',
      driver: CookieDriver
    });
  }
}

我们在这里定义了2个kurimudb类,一个是localstorage一个是cookie,我们可以在这里新增一些方法或者直接导出给controller用,因为即便你不新增方法也可以使用kurimudb内置的函数。

我们拥有kurimudb这样的库可以解决存储模块化的问题,我们不用关心这个缓存的key是否被使用过,只需要设置好唯一的name值,它就能给我们提供一组方便调用的api。另外kurimudb还有sessionstorage和indexDB的插件,如果业务需要可以快速的安装,然后声明一个新的类导出即可使用。

控制器

src/controller

在模板默认自带了一个user.ts例子,我们在上一个model中说明了apiModel和cacheModel,这里的controller就直接引入它们。并且在controller暴露入口。

import UserApiModel from '../model/api/user';
import { UserLocalStorage, UserCookie } from '../model/cache/user';

export default class UserController {
  private localStorageModel: UserLocalStorage;
  private cookieModel: UserCookie;
  private apiModel: UserApiModel;

  constructor() {
    this.apiModel = new UserApiModel();
    this.localStorageModel = new UserLocalStorage();
    this.cookieModel = new UserCookie();
  }
  async login(req: TUserModel.ReqLogin): TUserModel.ResLogin {
    return await this.apiModel.login(req);
  }
}

控制器我们还可以对api/cache获取的数据做处理,比如说,后端返回的数据格式前端不便直接展示,我们应该在controller需要做一层转译,比如像这样:

transform(): { text: string; value: string }[] {
    const data = {
      '0': '小明',
      '1': '小红'
    };
    let _arr = [];
    let key: keyof typeof data;
    for (key in data) {
      _arr.push({
        text: data[key],
        value: key
      });
    }
    return _arr;
  }

视图(.vue)

以vue来举例,我们如何在视图优雅的调用controller?并且如何使用@types定义的类型来巩固我们的组件?

import TUserApiModel from '../../@types/model/api/user';

const login = async (params: TUserModel.ReqLogin) => {
  await userController.login(params);
};

// 调用login函数
login({
  captcha: "",
  password: "",
  username: "",
  uuid: ""
})

当调用login函数时候,提供了与ReqLogin不符合的数据结构,是会出现报错的。同理,我们调用cache也是一样,需要在controller把cache封装一层暴露给vue即可。

环境变量

可以根据业务需要,建立业务相关的 env 环境(模式)。 vite-模式文档

以下是根目录默认提供了 3 个环境文件,对应了本地,测试,生产环境

  1. .env
  2. .env.dev
  3. .env.prod

内容示例: 根据业务需要进行配置

VITE_APP_API=
VITE_APP_SECRET=

那么同理,如果业务需要额外增加新的自定义环境变量,则需要在 src/vite-env.d.ts 中重新定义类型:

/// <reference types="vite/client" />
interface ImportMetaEnv {
  VITE_APP_API: string;
  VITE_APP_SECRET: string;
  // 新的环境变量的定义写这里
}

Mock

使用vite-plugin-mock来做本地开发的mock,模板暂时没有内置生产环境的mock。

// vite.config.ts
viteMockServe({
  localEnabled: true //是否开启本地的mock功能
}),

定义mock api:

// /mock/user.ts

import { MockMethod } from 'vite-plugin-mock';
export default [
  {
    url: '/api/get',
    method: 'get',
    response: (res: any) => {
      return {
        code: 0,
        data: {
          name: 'this is mock name'
        }
      };
    }
  }
] as MockMethod[];

其他的库

  1. dayjs
  2. axios
  3. vueuse
  4. kurimudb
  5. query-string

最近很忙,一天被排的满满的。担心身体会被拖累,最近脑部眩晕的次数越来越多了,我想可能是偶尔晚上不吃饭而且高强度思考的原因吧。作息可能要调整一点了,务必要早睡,晚睡早起看书真的看不进去。

就这样 晚安

请输入图片描述

原文链接-因卓诶-人类高质量男性开发的基于TS且自带运行时校验的unicloud云函数是什么样子的?

前言

去年年底在上一家团队的伦哥和我提到了TypeScript的运行时校验,当时由于没有使用TS开发过后端,所以也就不太关心这个事情。但是今年开发TS后端,尤其是最近重构剑指题解开源项目的v
版本接口的时候,才觉得我必须要上运行时检测了。这篇文章内容不会很长(由于时间紧迫,我就简明扼要的写),我会从现有的云函数开始,然后和大家一步一步复盘改造细节。

改造开始

改造之前你需要了解为什么需要运行时检测?目前运行时检测有哪些方案,他们分别有什么弊端?
Nodejs开发中和我们客户端js开发都有共同问题,就是“undefined”,报各种定义找不到,而且后端规定API参数的时候很头疼。
往往要写这样繁琐的代码进行类型安全的控制:

// 添加文章
  async addArticle() {
    return handleMustRequireParam(
      [
        {
          key: 'title',
          value: '文章标题'
        },
        {
          key: 'content',
          value: 'content内容'
        },
        {
          key: 'tagID',
          value: '标签内容'
        },
        {
          key: 'desc',
          value: '描述'
        }
      ],
      this.event.params
    )
      .then(async () => await this.handler('addArticle'))
      .catch((err) => err);
  }

handleMustRequireParam这个方法是定义的一个函数,用于检测必传参数是否未传递或者为空。在每一个云函数中我们都要写这样一大段非常臃肿的代码。而且客户端鬼知道会给你传递什么乱七八糟的参数(这种情况在unicloud 文档云数据库经常出现)。所以swrod开源项目升级了explain.js到v2版本,加入了动态类型校验的中间件用来解决这个问题。

目前的运行检测方案你可以看一下这篇文章,ts运行时检测
看完之后,其实最大的弊端就是它不支持复杂类型校验,我如果想要写如下的代码,以前的方案就不支持我们这样做

interface Test{
  code: string;
  flag: string;
}

type IApiRes = Pick<Test, 'code' | 'flag'>

类似Pick, Partial这样高级的TS泛型在开发中经常用,但是现在很少有一个库能够解决这样的问题。
综合上述,我们使用了tsrpc框架中的核心库: tsbuffer-validator

这个库目前是没有文档的,这次复盘所有的代码都是看test测试用例推出来的,感谢作者大大持续帮我解决开发中各种问题

如果是经常关注我博客的水友都知道,我在前段时间写了一个垃圾的教程专门用来入门tsrpc框架,戳这里去看,tsrpc中最亮眼的ts运行时检测功能就是tsbuffer-validator这个库提供功能。

在浏览了这个库的test用例之后,我这样去开发:

1. 使用tsbuffer-proto-generator这个库将proto转换成schemas.json
2. 添加一个模块去做校验功能,模块中参数就是生成出来的schemas.json和当前触发api路由

首先我们定义proto,去写一个简单的ts代码

// proto/question.ts

export interface AddQuestion {
  title: string;
  areaID: string;
  content: string;
  tagID: string[];
}

我们定义了一个[添加题目]的api请求类型,而实际上我们在云函数路由中是question/addQuestion,我们到时候在写中间件的时候,要记得做一下第一个字母大写的处理,否则会找不到我们写的这个请求类型。

然后我们开始生成schemas.json

npm i tsbuffer-proto-generator --save-dev
这个模块建议安装到云函数之外,即你的工程最外面,不要安装在云函数内部

然后我们在云函数根目录去新建一个schemas文件夹

// schemas/genSchemas.js

const { TSBufferProtoGenerator } = require('tsbuffer-proto-generator');
const glob = require('glob');
const path = require('path');
const fs = require('fs');

async function main() {
  let generator = new TSBufferProtoGenerator({
    baseDir: path.resolve(__dirname, '..', 'proto')
  });

  let files = glob.sync('**/*.ts', {
    cwd: path.resolve(__dirname, '..', 'proto')
  });
  console.log('Files: ', files);

  let result = await generator.generate(files);

  fs.writeFileSync(path.resolve(__dirname, 'schemas.json'), JSON.stringify(result, null, 2));
}
main();

轮到我们的nodemon工具人登场,我们利用nodemon去监听proto文件夹协议的更改,从而触发genSchemas.js。

// nodemon.proto.json

{
  "watch": ["proto"],
  "ext": "ts",
  "exec": "node schemas/genSchemas.js",
  "legacyWatch": true
}

package.json -> script

"proto": "nodemon --config nodemon.proto.json",

运行npm run proto之后就可以看到schemas文件夹中有一个schemas.json

{
  "question/AddQuestion": {
    "type": "Interface",
    "properties": [
      {
        "id": 0,
        "name": "title",
        "type": {
          "type": "String"
        }
      },
      {
        "id": 1,
        "name": "areaID",
        "type": {
          "type": "String"
        }
      },
      {
        "id": 2,
        "name": "content",
        "type": {
          "type": "String"
        }
      },
      {
        "id": 3,
        "name": "tagID",
        "type": {
          "type": "Array",
          "elementType": {
            "type": "String"
          }
        }
      }
    ]
  }
}

细心的你可能会发现对象中有一个key为 “question/AddQuestion”,我们等会写中间件的时候,就拿api的url去匹配这个key从而拿到api的schema

写一个名为tsbuffer-params-validate的中间件

const { TSBufferValidator } = require('tsbuffer-validator');

module.exports = function (event) {
  // schemas 由ts的proto生成的schemas
  // params 参数
  // service 路由url中的service
  // action 具体的方法
  const { schemas, params, service, action } = event;
  const validator = new TSBufferValidator(schemas);
  let vRes = validator.validate(params, `${service}/${action.replace(/^\S/, (s) => s.toUpperCase())}`);
  return vRes;
};

然后中间件会返回给我们结果:这个参数是否校验成功(如果出错误,会返回具体错误信息),然后我们就去云函数中去使用这个中间件。

    // 添加校验参数中间件
      app.use(async ({ event }) => {
        const validateResult = await ParamsValidate({
          ...event,
          params: event.data,
          schemas
        });
        if (!validateResult.isSucc) {
          // 将响应信息改为异常信息
          explain.response.body = {
            message: validateResult.error
          };
        }
      });

到此为止我们都已经改造好了,我们可以测试一下访问云函数具体路由的时候,会不会去校验参数:

"data": {
    "title": "",
    "areaID": "",
    "content": "",
    "tagID": [1]
},

如果我们传递一个这样的参数,中间件就会拦截,并且爆出这样的错误信息:

{
    "isSucc": false,
    "error": {
        "type": "TypeError",
        "params": ["string", "number"],
        "inner": {
            "property": ["tagID", "0"],
            "value": 1,
            "schema": {
                "type": "String"
            }
        }
    }
}

提示我们的tagID需要是string[],而不是number[]。

结束

这篇文章内容很简单,由于很多库没有文档,我还是花了一部分时间去推敲研究的。而且用tsrpc核心库的人太少了,这么好的东西必须要分享给大家,而且在unicloud领域,使用ts开发的人本来就是稀有,所以这篇文章的种种技巧都能实打实的解决各位云函数开发者的大问题,希望大家能用到工程上,用完就懂运行时检测类型有多香了。