自定义函数中Zod对象键的类型推断

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

我正在创建一个名为

createDefinition
的函数,它以 Zod 对象作为参数,使用
ZodType
来缩小可以传递给它的允许的 Zod 形状(在本例中,仅使用 JSON)。

但是,因为这个函数always需要一个

z.object()
并且会被调用很多次,所以最好只将传递对象的内部属性作为参数,以避免每次都键入
z.object()
想要调用
createDefinition
 — 为了方便起见,它将在其内部调用
z.object({ ...passedProps })

我正在努力以创建类型兼容的 Zod 对象的方式键入我的函数输入(请参阅下面的版本 2)。

版本一(有效,但需要将
z.object()
传递给它):

type Result<S extends JsonObject> = {
  _schema: ZodType<S>;
};

export const createDefinition = <Shape extends JsonObject>(
  schema: z.ZodType<Shape>,
): Result<Shape> => {
  // ... Do stuff
  return {
    _schema: schema,
  };
};

createDefinition(z.object({
  string: z.string(),
  date: z.date(), // TypeError -> as expected
}));

版本二(便捷版),不起作用:

type Result<S extends JsonObject> = {
  _schema: ZodType<S>;
};

export const createDefinition = <Shape extends JsonObject>(
  schemaProperties: {
    [K in keyof Shape]: z.ZodType<Shape[K]>,
  }
): Result<Shape> => {
  const schema = z.object(schemaProperties);
  // ... Do stuff
  return {
    _schema: schema, // Type error :: `schema` doesn't match ZodType<Shape>
  };
};

createDefinition({
  string: z.string(),
  date: z.date(), // No TypeError?
});
typescript type-inference zod
1个回答
0
投票

z.object
接受
ZodRawShape
,它是具有
ZodTypeAny
值的对象。我们需要将这些值限制为 Zod 类型以获得有效的 JSON 值类型。

这里有一种方法,通过定义 JSON 值的类型并将其传递给

ZodRawShape
来定义新的更窄的
ZodType
等价物。然后我们可以使用新的形状类型作为我们的通用参数类型。

import { z, ZodType } from 'zod';

type JsonValue = string | number | boolean | Array<JsonValue> | JsonObject;
type JsonObject = { [x: string]: JsonValue };

type ZodRawJsonShape = Record<string, ZodType<JsonValue>>;

function createDefinition<T extends ZodRawJsonShape>(schema: T) {
  return z.object(schema);
};

const valid = createDefinition({
  a: z.string(),
  b: z.number(),
  c: z.array(z.string()),
  d: z.object({ foo: z.array(z.string()) })
})

const invalid = createDefinition({
  a: z.string(),
  b: z.object({
    foo: z.string(),
  }),
  c: z.date(), // Error
  d: z.array(z.date()) // Error
  e: z.object({ // Error
    bar: z.date()
  })
});

游乐场

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