Zod:使用现有类型创建模式

Dot*_*tan 27 typescript zod

我有一个端点应该获取一个method应该符合 Axios type 的参数Method

如何使用 Zod 创建一个架构来验证该值是否使用该类型Schema

import { Method } from 'axios';

const Schema = zod.object({
  method: zod.someHowUseTheTypeFrom(Method),
});
Run Code Online (Sandbox Code Playgroud)

MethodAxios 包中的类型是:

export type Method =
  | 'get' | 'GET'
  | 'delete' | 'DELETE'
  | 'head' | 'HEAD'
  | 'options' | 'OPTIONS'
  | 'post' | 'POST'
  | 'put' | 'PUT'
  | 'patch' | 'PATCH'
  | 'purge' | 'PURGE'
  | 'link' | 'LINK'
  | 'unlink' | 'UNLINK'
Run Code Online (Sandbox Code Playgroud)

Sou*_*man 22

阅读您的评论,听起来您想确保您的架构与 axios 的类型同步Method。我建议执行以下操作:

import { z } from 'zod';
import type { Method } from 'axios';

const methods: z.ZodType<Method> = z.enum(['get', 'GET', ...]);
Run Code Online (Sandbox Code Playgroud)

这至少会强制表达式右侧的模式解析有效的 axiosMethod结果。axios不幸的是,除非还导出包含与类型中的值相对应的字符串的数组,否则任何其他操作都可能无法实现Method

您正在寻找的原始内容z.something(<type here>)无法工作,因为 zod 正在使用实际的运行时对象,并且诸如此类的类型Method在运行时不存在。如果axios导出一个包含方法的数组,那么这是一个运行时值,您可以使用它(可能通过某种类型转换)来生成您的methods架构(稍后会详细介绍)。

这种方法的另一个缺点是,类似这样的事情将进行类型检查:

const methods z.ZodType<Method> = z.enum(['get']);
Run Code Online (Sandbox Code Playgroud)

其原因在于类型在 TypeScript 中的工作方式。该enum模式只会成功解析'get'但由于文字'get'是 中定义的较大联合类型的子类型Method,因此生成的模式也是可分配的。

因此,我要提出的下一个选项感觉有点弄巧成拙,因为它需要重新声明 中的所有值Method,但是,您可以继续使用该axios Method类型,并且您肯定会拥有一个解析所有值的模式在Method(即,不屈服于上述问题):

import { z } from "zod";
import { Method } from "axios";

const METHOD_MAP: { [K in Method]: null } = {
  get: null,
  GET: null,
  delete: null,
  DELETE: null,
  head: null,
  HEAD: null,
  options: null,
  OPTIONS: null,
  post: null,
  POST: null,
  put: null,
  PUT: null,
  patch: null,
  PATCH: null,
  purge: null,
  PURGE: null,
  link: null,
  LINK: null,
  unlink: null,
  UNLINK: null
};

const METHODS = (Object.keys(METHOD_MAP) as unknown) as readonly [
  Method,
  ...Method[]
];
const methods: z.ZodType<Method> = z.enum(METHODS);
Run Code Online (Sandbox Code Playgroud)

的类型断言METHODS在这里是安全的,因为METHODS_MAP不会导出,并且我们确切地知道它有哪些键。现在,如果缺少METHOD_MAP任何值,该对象将导致类型错误,但这意味着生成的模式将解析所有值作为编译时强制执行的保证。MethodMethod

  • 感谢您的解决方案!您是否有理由不跳过“METHODS”并使用“z.nativeEnum”?在您的示例中,假设您还在“METHOD_MAP”的每个条目上设置了一个字符串值,您不能只执行“z.nativeEnum(METHOD_MAP)”吗?还需要将其类型更改为“{ [K in Method]: K }”。 (2认同)

小智 8

我发现 usingz.custom<ExistingType>()对我有用,并且适合解决此类问题。

[已编辑] 根据@esteban-toress的说法,我们仍然需要在末尾添加一个验证函数,如下所示z.custom<ExistingType>((value) => //do something & return a boolean)。否则,z.custom<ExistingType>()只返回ZodAny允许值的类型any

请参阅文档: https://zod.dev/?id =custom-schemas