loading...

# 介绍

# 定位

ZodUI 可以使你进行简单并且类型安全的代码编写的同时去生成对应的 UI,通过 Zod 对输入进行校验并进行描述,同时你也可以扩展语法特性与展示效果达到你所设想的模样。
相对于其他的低代码平台,ZodUI 更加注重于代码的可维护性与可扩展性,我们更愿意去做开发者手里的锄头。

输入:用户通过交互对组件进行数据的输入,或者是后端数据,又或者是随机数据。

本工具便试图找到一个从代码开发者角度来切入解决开发代码重复的问题,通过定义类型得到交互,通过定义类型之间的关系得到元素的展示规则,通过定义类型的规则得到数据的校验规则。
那么!所有的一切我们便都可以从类型中得到。

# 什么是 Zod ?

对于部分人来说 Zod 听起来似乎有点陌生,在这里我们对他进行一个简单的概括:Zod 是一个用于描述数据的工具,它可以帮助你定义数据的类型,以及对数据进行校验。
Zod 的使用方式与 TypeScript 的类型定义非常相似,你可以通过定义一个 ZodType 来定义一个数据类型,然后通过 parse 方法来对数据进行校验,如果校验通过则返回对应的数据,否则抛出错误。

content_copy
import * as z from 'zod'

const schema = z.object({
  name: z.string(),
  age: z.number()
})

schema.parse({ name: 'zod', age: 18 })
// 解析正确
schema.parse({ name: 'zod', age: '18' })
// 解析错误,抛出错误

更多详细内容可阅读 Zod 文档

# 为什么不是 X ?

众所周知验证器也是一个卷到烂的赛道,那么为什么我们不使用它们而是选择了 Zod 呢?因为星星多。
那么首先,我们先基于我们的基本路线来假设我们如果需要一个工具,那么它应该是什么样子的。

  • API 合理,易于扩展定义。
  • 支持足够多的基础类型。
  • 支持自定义类型。
  • 能按照规则对数据进行校验,同时可以自定义校验规则。
  • 支持自定义错误信息。

# 为什么不是 yup ?

Yup 功能相对齐全,最开始使用 vanilla JS 实现,后来用 TypeScript 重写。

  • 支持类型的转化(Cast)和处理(Transform)
  • 默认情况下,所有字段都是可选的
  • 缺少 Promise 类型
  • 缺少 Function 类型
  • 缺少并集和交集类型

# 为什么不是 io-ts ?

数学家写的。

# 为什么不是 valibot ?

角度不同方向不一致,valibot 更多的是一个表单校验器,而 Zod 更多的是一个数据描述工具,我们更需要的是一个用来描绘数据,api 的设计上来说并不是很适合用于定制扩展系统。

# 为什么不是 JSON Schema ?

JSON Schema 对于实际的业务描述来说,它的表现力并不是很强,同时它的扩展性也不是很好,它更多的是一个用于描述 JSON 数据的工具,而不是用于描述真正交互数据的工具。
在边界和扩展性上来说,JSON Schema 并不是一个很好的选择。

# 为什么使用 ZodUI ?

如果你对 TypeScript 的类型系统有一定的了解,那么你无需担心你对 Zod 的了解,写 Zod 就像是在写 TypeScript 的类型一样自然而又简单。
当然你如果并不熟悉 TypeScript 的类型系统也不会对你带来任何的影响,你可以从数据定义 schema 的形式来认知这套系统,这也是十分简单的一个思路。

但同时 Zod 是一个纯粹去描述数据的工具,在 UI 视图上来说,并不单单是需要简单的数据描述。基于此需要对 Zod 进行了扩充定义,详情可参考 Zod External。在此基础上,你可以通过定义 Zod 描述来生成你需要的 UI。

  • 并且我们提供了一些常用的 UI 组件,你可以通过组合这些组件来生成你需要的 UI。
  • 在使用过程中可能涉及到特殊的 UI 控件以及展示形式,本项目支持通过自定义插件的方式来实现。
  • 同样的,对于已有的项目可能有着自己的样式、主题、组件库等,本项目也支持自定义它们。

# 简单的例子

我们先来看一个简单的例子,当需要一个表单,该表单包含一个字符串输入框与数字输入框,我们可以通过定义如下的 zod 描述来生成我们需要的 UI。

content_copy
z.object({
  name: z
    .string()
    .label('名称'),
  age: z
    .number()
    .label('年龄')
})

上面这段代码生成的数据对象传递给给我们的渲染组件后,我们可以得到如下的内容:

code
play_arrow
chevron_right
content_copy
z.object({
  name: z
    .string()
    .label('名称'),
  age: z
    .number()
    .label('年龄')
})
loading...
expand_more

接下来就让我们一起来享受由类型驱动视图的快乐吧🎆🎆🎆!

arrow_upward
comment

摘要