Home > Blockchain >  How to get inferred type of dynamically returned value based on passed Zod schema object?
How to get inferred type of dynamically returned value based on passed Zod schema object?

Time:01-06

I have a function that randomly returns one of these objects:
{ name: "Tommy", age: 15 }
{ car: "BMW" }

Let's say I want to run this function and hope that it returns me the User object instead of the Car. To verify this I want to pass it Zod schema as an argument so the function will parse it and throw an error if the random object doesn't match my schema.
Otherwise, if the random object matches schema, I want to get this object returned from the function with the inferred type so I know that i have name and age properties.

That's my code:

import { z } from "zod";

const User = z.object({
  name: z.string(),
  age: z.number()
});

const randomObjects = [
  {
    name: "Tommy",
    age: 16
  },
  {
    car: "BMW"
  }
];

export const getRandomObject = (
  Schema: z.AnyZodObject
): z.infer<typeof Schema> => {
  try {
    const obj = Math.random() > 0.5 ? randomObjects[0] : randomObjects[1];

    Schema.parse(obj);

    return obj;
  } catch (error) {
    throw new Error("Sorry, wrong Schema passed");
  }
};

const user = getRandomObject(User);
console.log(user);

user is being inferred as { [x: string]: any; }.
How to make typescript know that it is an User object with name and age properties?

Codesandbox: https://codesandbox.io/s/zod-v3g3hp?file=/src/index.ts:513-735

CodePudding user response:

You should be using a generic parameter so that TS can infer the schema type and reuse it:

export const getRandomObject = <S extends z.AnyZodObject>(
  Schema: S
): z.infer<S> => {

Forked sandbox

CodePudding user response:

To infer the type of the returned object as User, you can use the infer type utility provided by zod and pass it the User schema as a type parameter.

Here is an example of how you can modify your code to correctly infer the type of the returned object:

import { z } from "zod";

const User = z.object({
  name: z.string(),
  age: z.number()
});

const randomObjects = [
  {
    name: "Tommy",
    age: 16
  },
  {
    car: "BMW"
  }
];

export const getRandomObject = (
  Schema: z.AnyZodObject
): z.infer<typeof Schema> => {
  try {
    const obj = Math.random() > 0.5 ? randomObjects[0] : randomObjects[1];

    Schema.parse(obj);

    return obj;
  } catch (error) {
    throw new Error("Sorry, wrong Schema passed");
  }
};

const user = getRandomObject(User);
console.log(user);

With this change, the type of the user variable will be inferred as User, so you will have access to the name and age properties of the returned object.

  • Related