【问题标题】:How to transform a recursive generic's shape (typescript)如何转换递归泛型的形状(打字稿)
【发布时间】:2021-09-25 20:11:43
【问题描述】:

我喜欢 Zod 解析器,但我可能在创建表单库时不知所措。

在理想的最终状态下,输入形状被转换为创建{ fieldA: { value, onChange, errors } }。它适用于单个级别,但不清楚如何支持数组和嵌套对象。

typescript 可以像这样转换递归泛型吗?

Zod 表示这样的解析器:

const schema = z
  .object({
    name: z.string().min(3, 'Too short.'),
    nested: z.object({
      name: z.string(),
    }),
    repeat: z.array(z.object({
      arrNest: z.string(),
    })),
  }).transform((v) => v.name);

然后使用类型推断:

const example = <Input extends { [v: string]: any }, Output extends unknown>(
  schema: z.ZodType<Output, any, Input>
) => {
  type Fields = {
    [P in keyof Input]: {
      value: Input[P];
    };
  };

  return ({} as unknown) as Fields;
};

export const typed = example(schema);

名称具有所需的类型{ value: string },但重复具有:

相反,我想用对象和数组递归地应用它

然后types.repeat 将具有类型{ arrNest: { value: string } }[]

注意事项

zod object type 相当复杂..

但我只关心Input,表示为

export type ZodRawShape = { [k: string]: ZodTypeAny };

欢迎任何关于可行性或方向的想法!

【问题讨论】:

  • 我对你的example 函数有点困惑,你为什么不能直接使用type MySchema = z.infer&lt;typeof schema&gt;
  • 我正在编写一个可以重用的函数,也许z.infer 在这里更好,但我仍然需要更改所有原语的类型。例如,我将 object({ fieldA: number }) 转换为 { fieldA: { value: number, onChange: (a: number) =&gt; void, errors } } 我想自动生成输入道具。
  • 您能否进一步解释一下您希望如何将类型更改为fieldA: { value...?我不明白它是如何工作的,所以你想最终得到一个具有namenestedrepeat 属性的对象?他们每个人都应该是一个带有{ value, onChange, errors }但输入正确的对象?
  • 我实际上已经这样做了。下一个级别是拥有nested.name = { value, onChange, errors }。此外,这是关于获取编译器推断的类型。我知道如何在 javascript 中完成此操作。

标签: typescript typescript-generics zod


【解决方案1】:

我不能 100% 确定我是否正确理解了您的需求,但输入条件 + 推断应该可以到达您想要的位置。像这样的:

function example<Input extends { [v: string]: any }>(i: Input) {
  type Fields<I> = {
    [P in keyof I]: I[P] extends object
      ? Fields<I[P]>
      : I extends Array<infer A>
        ? Fields<A>[]
        : { value: I[P] }
  };

  return i as Fields<Input>;
}

type Input = {
  toto: number;
  nested: { tutu: string };
  array: { stuff: boolean }[];
};

const typed = example({} as Input);

typed.array[0].stuff.value = true;
typed.toto.value = 13;
typed.nested.tutu.value = 'dojz';

我使用原始对象作为输入,因此您需要将其调整为 Zod,但如果您知道 Zod 对象的结构,这应该不会太难。 也许使用Fields&lt;zod.infer&lt;typeof schema&gt;&gt; 更接近你真正需要的。

【讨论】:

    猜你喜欢
    • 2018-12-17
    • 2021-06-30
    • 2015-11-27
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 2021-11-26
    • 2021-11-20
    相关资源
    最近更新 更多