Is there a function in Zod similar to Yup's oneOf()?

If I wanted to restrict a property to specific values using Yup, it could be achieved with the code snippet below:

prop: Yup.string().oneOf([5, 10, 15])

However, I haven't found a similar method in Zod. Nonetheless, I can still validate it by:

const allowedValues = [5, 10, 15];

const schema = z.object({
  prop: z.number().superRefine((val, ctx) => {
    if (allowedValues.includes(val)) return true;

    ctx.addIssue({
      message: `${ctx.path} must be one of ${allowedValues}`,
       code: "custom",
    });
    return false;
  }),
});

Is there a way to achieve this with less code?

Answer №1

If you encounter a similar situation, one approach is to utilize z.union along with z.literal to make the code more declarative:

const schema = z.object({
  prop: z.union([z.literal(5), z.literal(10), z.literal(15)]),
});

This method also offers the advantage of defining the exact type 5 | 10 | 15 as the output rather than just number.

However, writing this out can become cumbersome, so it might be beneficial to create a helper function if you find yourself repeating this frequently:

// While this signature may seem excessive, it encompasses all types that
// z.literal can work with.
function oneOf<T extends string | number | boolean | bigint | null | undefined>(
  t: readonly [T, T, ...T[]],
) {
  // Since a union necessitates at least 2 elements for proper typing,
  // it must be instantiated in this manner.
  return z.union([
    z.literal(t[0]),
    z.literal(t[1]),
    // We cannot use pointfree syntax here since z.literal accepts an optional second parameter
    ...t.slice(2).map(v => z.literal(v)),
  ])
}

// Using this will result in a schema equivalent to the initial example
const schema2 = z.object({
  // Without 'as const', this will still pass type checking but with looser 
  // types compared to the first scenario.
  prop: oneOf([5,10,15] as const),
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you explain the significance of the @ symbol in TypeScript/Vue?

I've recently embarked on a new VueJS project and stumbled upon some unfamiliar syntax. I have highlighted the lines with comments below. file(example) : MyModule.vue const storeCompte = namespace("compte") // namespace is based on 'no ...

Function in Typescript that accepts either a single object or an array of objects

We frequently use a simple function declaration where the function can accept either a single object or an array of objects of a certain type. The basic declaration looks like this: interface ISomeInterface { name: string; } class SomeClass { pu ...

Calling gtag("event") from an API route in NextJS

Is there a way to log an event on Google Analytics when an API route is accessed? Currently, my gtag implementation looks like this: export const logEvent = ({ action, category, label, value }: LogEventProps) => { (window as any).gtag("event&quo ...

Error encountered in Vue 3 typescript: Uncaught TypeError - this.$on function is not defined in this context

Just set up a fresh installation of Vue 3 using vue-cli and typescript. Everything seems to be running smoothly, but as soon as I incorporate the https://vue-select.org/ package, I encounter this error in the browser console: Uncaught (in promise) TypeErro ...

Asynchronous function in TypeScript is restricting the return type to only one promise type

Using node version 14.7.0, npm version 6.14.7, and typescript version 3.7.3. I have a function that interacts with a postgres database and retrieves either the first row it finds or all results based on a parameter. It looks something like this: async fet ...

Tips on creating an object within a TypeScript interface

As a newcomer to Type Script, I am curious if there is a way to specify in the interface "IIndex" that SystemStatus is an object with properties Data and DataUrl. Currently, it appears that SystemStatus is undefined. interface IIndex extends ng.IScope { ...

What is the best way to enable code sharing between two TypeScript projects housed within the same repository?

Our project has the following structure: api (dir) -- package.json -- tsconfig.json -- src (dir) -- client (dir) ---- package.json ---- tsconfig.json ---- src (dir) The "client" directory houses a create-react-app project that proxies to the API d ...

Ways to grant access beyond the local host

I am having trouble accessing my Angular2 application outside of localhost. I can easily navigate to localhost:3030/panel, but when I try to use my IP address like 10.123.14.12:3030/panel/, it does not work. Can someone please help me fix this issue? I am ...

Are fp-ts and Jest the perfect pairing for testing Option and Either types with ease?

When working with fp-ts, and conducting unit tests using Jest, I often come across scenarios where I need to test nullable results, typically represented by Option or Either (usually in array find operations). What is the most efficient way to ensure that ...

The design of Next.js takes the spotlight away from the actual content on the

Recently, I've been working on implementing the Bottom Navigation feature from material-ui into my Next.js application. Unfortunately, I encountered an issue where the navigation bar was overshadowing the content at the bottom of the page. Despite my ...

Workspace Settings cannot be saved due to an unregistered configuration

I've been attempting to change the StatusBar color in VScode Setting.json using Configuration and Workspace. However, I encountered an error when trying to make the update: Error: Unable to write to Workspace Settings because workbench.colorCustomizat ...

Error message displaying Angular Service not able to be injected into component: StaticInjectorError in AppModule

I'm currently attempting to inject a SpotifyService service into a SearchComponent component, where the service requires Http as a parameter. Below is my module setup: @NgModule({ imports: [ BrowserModule, FormsModule, RouterModule ], decla ...

How to verify if an unknown-type variable in TypeScript contains a specific property

When using typescript with relay, the props passed down are of type unknown. Despite my efforts, I am unable to persuade the compiler that it can have some properties without encountering an error: <QueryRenderer environment={environment} query={te ...

How can I call a global function in Angular 8?

Currently implementing Angular 8, my objective is to utilize downloaded SVG icons through a .js library. To achieve this, I have made the necessary additions to my .angular.json file: "scripts": [ "node_modules/csspatternlibrary3/js/site ...

Trouble arises with connect-mongo, passport, and passport-local-mongoose as session fails to persist

Seeking assistance with saving session and incorporating functionality like req.isAuthenticated(), req.user, etc., but unable to make it work. Session does not persist and seems to be malfunctioning for unknown reasons. app.ts https://pastebin.com/yGvUZh ...

Customizing the MUI Select component with TypeScript

What seems to be the issue in this code snippet? TS2322: Type '(event: SelectChangeEvent) => void' is not assignable to type '(event: SelectChangeEvent<unknown>, child: ReactNode) => void'.   Types of parameters 'even ...

Show the subscription response data in Angular

When utilizing the code snippets below from two different components, I am able to receive a valid response value from the subscriber. dataService.ts fetchFormData(){ return this.http.get('http://localhost:48116/RecuruitmentService.asmx/addRoleTest ...

Using TypeScript to define task invocation parameters with AWS CDK's CfnMaintenanceWindowTask

Currently, I am utilizing AWS CDK along with the library @aws-cdk/aws-ssm and TypeScript to construct CfnMaintenanceWindowTask. The code example I am working on is derived from AWS CloudFormation documentation, specifically for "Create a Run Command t ...

What is the best way to choose a key from a discriminated union type?

I have a discriminated union with different types type MyDUnion = { type: "anonymous"; name: string } | { type: "google"; idToken: string }; I am trying to directly access the 'name' key from the discriminator union, like thi ...

Is this Firebase regulation accurate and suitable for PUT and GET requests in an Angular and Firebase environment?

Creating a system where users can only see their own posts and no one else can access them is my main goal. Authentication along with posting functionality is already in place and working, but I want to implement this without using Firebase restrictions. ...