Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

z.union allow ZodType array spread as argument #3383

Open
FlynnHillier opened this issue Apr 5, 2024 · 2 comments
Open

z.union allow ZodType array spread as argument #3383

FlynnHillier opened this issue Apr 5, 2024 · 2 comments

Comments

@FlynnHillier
Copy link

FlynnHillier commented Apr 5, 2024

I am attempting to use a dynamically generated array of strings to define a z.union() that validates that a string is included within said dynamic array.

To do this I am mapping each element of my dynamic array of strings to z.literal(), and then spreading this mapped array of literals to the union type.

import { z } from "zod"
const TILES = ["a1","a2","a3","b1","b2","b3"]

// ERROR:
// Argument of type 'ZodLiteral<string>[]' is not assignable to parameter of type 'readonly [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]]'.
// Source provides no match for required element at position 0 in target.ts(2345)
const myUnion = z.union([
    ...TILES.map(tile => z.literal(tile))
])

This implementation results in typescript kicking up a fuss, as it is not sure that union has been provided any values. This is because zod's union type is hardcoded to have atleast 2 ZodTypes provided to it.

declare const unionType: <T extends readonly [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]]>(types: T, params?: RawCreateParams) => ZodUnion<T>;

This means to prevent typescript from complaining, 2 literals must be hardcoded before we spread our array of literals into the union.

const myUnion = z.union([
    z.literal("a1"),
    z.literal("a2"),
    ...TILES.map(tile => z.literal(tile))
])

This is evidently not ideal as we may not have two values which we always wish to be included in our union type.

Is there any way z.union() could be re-typed / changed in some way to better support spreading of ZodType arrays?

@extradosages
Copy link

This is a good idea; one-element and even zero-element unions have reasonable conventional semantics, and can probably be easily implemented in the type system with conditionals!

@colinhacks
Copy link
Owner

colinhacks commented Apr 29, 2024

My goal was for ZodUnion to have a strongly typed tuple containing the element schemas. The current type signature is designed to prevent things like your TILES.map() call, because then you can't do something like this:

myUnion.options[2]; 
// should be ZodLiteral<"a3">

I'm looking into loosening this restriction in the next major version. This is a recurring issue for people, and it doesn't impact the inferred type so it's probably not worth the trouble.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants