TypeScript:zod 模式验证的通用函数返回类型推断问题

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

我使用

zod
库进行模式验证,并定义了两个模式:
FormFactorDevice
FormFactor
。我还实现了一个
selectFormFactorDevice
函数,根据给定的
FormFactorDevice
deviceType
对象中选择一个值。

但是,

selectFormFactorDevice
的返回值被推断为
any
类型,而我希望它是
string | undefined
,因为我使用
z.string()
作为
fieldSchema
参数。

这是代码:

export const FormFactorDevice = <T extends z.ZodTypeAny>(fieldSchema: T) =>
  z.object({
    all: z.optional(fieldSchema),
    phone: z.optional(fieldSchema),
    smalltablet: z.optional(fieldSchema),
    tablet: z.optional(fieldSchema),
    laptop: z.optional(fieldSchema),
    desktop: z.optional(fieldSchema),
  });

export const FormFactor = <Z extends z.ZodTypeAny>(fieldSchema: Z) =>
  z.object({
    isFormFactor: z.literal(true).default(true),
    all: z.optional(fieldSchema),
    landscape: z.optional(FormFactorDevice(fieldSchema)),
    portrait: z.optional(FormFactorDevice(fieldSchema)),
  });

// FormFactorDevice could receive very complicated schema
const b = FormFactorDevice(z.string()).parse({
  all: '100',
  smalltablet: '200',
  phone: '300',
});

export const selectFormFactorDevice = <T extends z.ZodTypeAny>(
  formFactorDevice: z.infer<ReturnType<typeof FormFactorDevice<T>>>,
  deviceType: 'all' | 'phone' | 'smalltablet' | 'tablet' | 'laptop' | 'desktop'
): z.infer<T> | undefined => {
  return formFactorDevice[deviceType];
};

const d = selectFormFactorDevice(b, 'all'); // d is inferred as `any` type

如何修改

selectFormFactorDevice
函数以返回正确的类型(在本例中为
string | undefined
)?

注意:我尝试使用 z.infer 和 ReturnType 来推断正确的类型,但它似乎不起作用。 selectFormFactorDevice 的返回值被推断为任何类型,而我希望它是 string |未定义,因为我使用 z.string() 作为 fieldSchema 参数。

我知道

selectFormFactorDevice<z.ZodString>(b, 'all')
应该可以工作,但我希望我的函数足够智能以自动推断类型

您可以尝试将代码复制并粘贴到此处的 zod Playground:https://stackblitz.com/edit/typescript-rqwgxo?file=index.ts

reactjs typescript zod
1个回答
0
投票

selectFormFactorDevice
函数的实现非常简单(它只是一个属性访问)。我假设你想让它的打字做两件事:

  1. 推断正确的返回类型。
  2. 将第一个参数限制为已由使用
    FormFactorDevice
    函数创建的模式解析的对象。

我认为这些类型至少可以很好地满足这两个要求:

export const selectFormFactorDevice = <
  TFormFactorDevice extends z.infer<
    ReturnType<typeof FormFactorDevice<ZodTypeAny>>
  >,
  TDeviceType extends
    | 'all'
    | 'phone'
    | 'smalltablet'
    | 'tablet'
    | 'laptop'
    | 'desktop'
>(
  formFactorDevice: TFormFactorDevice,
  deviceType: TDeviceType
) => {
  return formFactorDevice[deviceType];
};

TFormFactorDevice
的约束表达了第 1 点(尽管它可能以不完整的方式实现;我不是 Zod 类型方面的专家)。对
TDeviceType
使用泛型参数
deviceType
可确保正确推断返回类型(第 2 点);它就变成了
TFormFactorDevice[TDeviceType]

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