Zod 返回类型的 object.keysof() 未键入

问题描述 投票:0回答:1

我正在尝试创建一个函数,它接收一个 zod 对象并通过

keyof()
函数返回一个 zod 枚举。

我目前拥有的是:

const FormSchema = z.object({
  username: z.string().trim().min(1).max(20),
  password: z.string().trim().min(12).max(100),
  rememberMe: z.coerce.boolean().optional().default(false),
  redirectTo: z.string().trim().startsWith("/"),
});

type Schema<T extends z.AnyZodObject> = z.infer<T>
type SchemaEnum<T extends z.AnyZodObject> = ReturnType<T["keyof"]>;

function getEnumFromSchema<T extends z.AnyZodObject> (schema: T): SchemaEnum<T> {
  const shape = schema._type;
  return shape.keyof();
}

function test () {
  const t = getEnumFromSchema(FormSchema);
}

当鼠标悬停在 codesandbox 上时,highliter 会显示以下内容

t
const t: z.ZodEnum<["username", "password", "rememberMe", "redirectTo"]> 
这会返回一个枚举,但打字稿会抛出错误
Type 'ZodEnum<never>' is not assignable to type 'ReturnType<T["keyof"]>'.
我一直试图用这个来获得一片绿叶,但对我来说似乎有些不对,我看在上帝的份上,找不到我要去哪里错了.

见上面的描述。

javascript typescript type-inference zod
1个回答
0
投票

错误信息

类型“ZodEnum”不可分配给类型 '返回类型'

表示

keyof()
的推断类型不是你所期望的。问题可能是
keyof()
返回对象所有可能键的联合,这不是
z.enum()
的有效类型。

一个解决方案是使用

z.union()
方法为对象的每个键组合单独的
z.literal()
验证器。您可以使用
Object.keys(schema)
创建一个密钥数组,然后使用
map()
创建一个
z.literal()
验证器数组。然后,您可以将验证器数组传递给
z.union()
以创建最终的枚举验证器。

这是更新后的代码:

const FormSchema = z.object({
  username: z.string().trim().min(1).max(20),
  password: z.string().trim().min(12).max(100),
  rememberMe: z.coerce.boolean().optional().default(false),
  redirectTo: z.string().trim().startsWith("/"),
});

type Schema<T extends z.AnyZodObject> = z.infer<T>

function getEnumFromSchema<T extends z.AnyZodObject>(schema: T) {
  const keys = Object.keys(schema);
  const validators = keys.map((key) => z.literal(key));
  return z.union(validators);
}

function test() {
  const t = getEnumFromSchema(FormSchema);
  // t is inferred to be of type `z.ZodEnum<"username" | "password" | "rememberMe" | "redirectTo">`
}

请注意,您不再需要定义单独的

SchemaEnum
类型,因为
z.union(validators)
的推断类型是
z.ZodEnum<"username" | "password" | "rememberMe" | "redirectTo">
.

© www.soinside.com 2019 - 2024. All rights reserved.