Skip to content

类型杂技

我很羡慕类似tsrpc的、轻装上阵的类型系统,但这过于有魄力了一点

简而言之,就是把类型声明(interface/types)当schema用, 比如,声明一个请求 的interface,假设叫RequestBody, 那么请求体就会受到这个类型的制约(运行时)

但这也有问题,因为类型既要为前端提供类型,又要在后端当作类型,又要做 schema

这可能会导致需要非常多的类型定义:请求一份,响应一份,前端一份,后端一份

PS不依赖特定规范使用ts,有的时候就会束手束脚。

类型难题

最常见的是前后端中数据结构有所不同

随便举一个例子:

ts
class Strudent {
  name: string
  run() {

  }
}

class A {
  @Post('')
  test(@Body() student: Strudent, @Query('id') @Pipe('objectId') id: ObjectId) {

  }

}

前端我们真实输入的参数是

  1. 一个只有name的对象(没有方法),(后端中是一个类实例)
  2. 一个字符串(后端中是mongodbobjectId

类型欺骗

有一些很取巧的方法(也许不是个好办法),这些方法本质是去“欺骗” ts服务器

关于class

ts
import { toClass } from 'phecda-client'

request.A.test(toClass<Student>({ name: 'student name' }))

关于class或许有更好的办法,只要phecda-client中做出一个DeepOmitFunction或者DeepJson之类的泛型,就能搞定!但嵌套的类型会给可读性和性能造成一些麻烦,暂未实装(个人不会这个体操)

关于objectId

这种情况复杂得多,前后端操作的数据结构不一致,这需要后端配合! 换句话说,这里需要一个特殊的协议,既要让后端在管道中运行时转换,又要欺骗前端ts的类型

后端中设一个专门的pipe,标记为objectId,负责将xxxxx转化为new ObjectId(xxxxx)(运行时转换)

再提供一个方法(欺骗前端类型)

ts
function toObjectId(input: string): ObjectId {
  return input as any
}

然后前端

ts
import { toClass } from 'phecda-client'
import { toObjectId } from 'backend'
request.A.test(toClass({ name: 'student name' }), toObjectId('xxxx'))// 本质还是字符串,在管道中转为objectid

Released the MIT License.