Search code examples
typescriptzod

Wrong typings for z.enum


Hello everyone i have a code like this:

import { z } from 'zod'

const options = [
    ["a", { label: "A" }],
    ["b", { label: "B" }],
]  as const

export function optionsToEnum<T>(entries: ReadonlyArray<Readonly<[value: T, { label: string }]>>): [T, ...T[]] {
    const [firstValue, ...restValues] = entries.map(([value]) => value)

    return [firstValue, ...restValues]
}

const a = optionsToEnum(options) // typeof a is ["a" | "b", ...("a" | "b")[]] but i expected ["a", "b"]

z.enum(a)

Why typeof a is ["a" | "b", ...("a" | "b")[]] i expected ["a", "b"] and how to fix this?


Solution

  • Here is the corrected version that addresses the incorrectly typed variable a issue as well as callback signature mismatch with map function: Argument type ([value]: readonly [any]) => any is not assignable to parameter type <T>(value: Readonly<[T, {label: string}]>, index: number, array: Readonly<[T, {label: string}]>[]) => any :

    import { z } from 'zod';
    
    const options = [
        ["a", { label: "A" }],
        ["b", { label: "B" }],
    ] as const;
    
    type ValueOf<T> = T extends Readonly<[infer U, any]> ? U : never;
    
    export function optionsToEnum<T extends ReadonlyArray<Readonly<[any, { label: string }]>>>(entries: T): { [K in keyof T]: ValueOf<T[K]> } {
        return entries.map(([value, _]) => value);
    }
    
    const a = optionsToEnum(options);
    // typeof a = readonly ["a", "b"]
    
    z.enum(a);
    
    

    The problem was that type T was inferred for the entire array, not for individual types for each tuple element, and therefore was unified as type "a" | "b".