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?
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"
.