从数组 Zod 内对象的键推断类型

Her*_*ine 6 arrays typescript zod trpc.io

所以我想从 Zod 数组中的对象的键中获取类型。该数组也嵌套在一个对象中,只是让事情变得更加困难。

这是我遇到的问题的抽象视图:

const obj = z.object({
  nestedArray: z.array(z.object({ valueIWant: z.string() }))
})

// Should be of type z.ZodArray() now, but still is of type z.ZodObject
const arrayOfObjs = obj.pick({ nestedArray: true })

// Grab value in array through z.ZodArray().element
arrayOfObjs.element.pick({ valueIWant: true })
Run Code Online (Sandbox Code Playgroud)

在 Zod 中使用数组会发生什么:

// Type of z.ZodArray
const arr = z.array(z.object({ valueIWant: z.string() }))

const myValue = arr.element.pick({ valueIWant: true })
Run Code Online (Sandbox Code Playgroud)

这是我的实际问题:

我有一个返回以下对象的 API:

export const wordAPI = z.object({
  words: z.array(
    z.object({
      id: z.string(),
      word: z.string(),
      translation: z.string(),
      type: z.enum(['verb', 'adjective', 'noun'])
    })
  )
})
Run Code Online (Sandbox Code Playgroud)

在我的 tRPC 输入中,我希望允许按单词类型进行过滤。现在,我不得不重写z.enum(['verb', 'adjective', 'noun']),这不太好,因为它可能会在以后引入问题。如何通过数组推断单词的类型?

tRPC 端点:

export const translationsRouter = createRouter().query('get', {
  input: z.object({
    limit: z.number().default(10),
    avoid: z.array(z.string()).nullish(),
    wordType: z.enum(['verb', 'adjective', 'noun']).nullish() // <-- infer here
  }),
  [...]
})
Run Code Online (Sandbox Code Playgroud)

Sou*_*man 8

我建议这样做的方法是将字段wordType作为一个单独的模式提取出来,然后您可以在z.object. 喜欢:

const wordTypeSchema = z.enum(["verb", "adjective", "noun"]);
type WordType = z.infer<typeof wordTypeSchema>;
export const wordAPI = z.object({
  words: z.array(
    z.object({
      id: z.string(),
      word: z.string(),
      translation: z.string(),
      type: wordTypeSchema
    })
  )
});
Run Code Online (Sandbox Code Playgroud)

然后我会WordType在其他需要该值的地方使用该类型。

但是,可以从嵌套对象中提取类型,如下所示:

type WordAPI = z.infer<typeof wordAPI>;
type WordType = WordAPI['words'][number]['type'];
//    ^- This will include `| null` because you used `.nullable`
// If you don't want the | null you would need to say
type WordTypeNotNull = Exclude<WordType, null>;
Run Code Online (Sandbox Code Playgroud)

再次,我会推荐第一种方法,因为它更具可重用性,并且在对象形状发生变化时不易需要更新。