change array.map() output a type that zod enum can take

192 Views Asked by At

I have the following code

export const taxTypeArray = [
  {value: 'INCLUSIVE' as const, label: '外税'},
  {value: 'EXCLUSIVE' as const, label: '内税'},
]

const test = taxTypeArray.map((item) => item.value)

export const taxType = z.enum(test)

and it gives the following error:

Argument of type '("INCLUSIVE" | "EXCLUSIVE")[]' is not assignable to parameter of type 'readonly [string, ...string[]]'.

the reason is that the type of test needs to be

type ["INCLUSIVE", "EXCLUSIVE"]

but array.map outputs the following type

type ("INCLUSIVE" | "EXCLUSIVE")[]

Is there a way I can change it so that testis of a type that z.enum can take?
I'd like to keep the types intact so I'd rather not use the following:

const test = taxTypeArray.map((item) => item.value) as [string, ...string[]]
3

There are 3 best solutions below

0
On BEST ANSWER

I would not use .map to calculate the array, this contains JS logic. Use z.nativeEnum() and declare the TaxType TS enum. Keep code simple and with as little logic as possible.

import { z } from 'zod';t

enum TaxType {
    INCLUSIVE = 'INCLUSIVE',
    EXCLUSIVE = 'EXCLUSIVE'
}

export const taxTypeArray = [
    { value: TaxType.INCLUSIVE, label: '外税' },
    { value: TaxType.EXCLUSIVE, label: '内税' },
]

export const taxType = z.nativeEnum(TaxType);


console.log(taxType.parse(TaxType.EXCLUSIVE))
1
On

The z.enum() methods expect to have a Tuple as its parameter. The problem is that you are trying to pass an array.

If you can be sure that the taxTypeArray will contain at least one element, then you can use something like:

const test = taxTypeArray.map((item) => item.value);
export const taxType = z.enum([test[0], ...test.slice(1)])

This is especially useful if you obtain the taxTypeArray from a source that you cannot control, say an API and then you need to define a z.enum based on the response from the API. (Which was my case)

0
On

Altho it's probably not what most people are looking for I will try adding my solution.
In my case the taxTypeArray was called later, after taxType so there was no need to declare it beforehand.
I just changed the order to something like this:

export const taxType = z.enum(["INCLUSIVE", "EXCLUSIVE"])

// ... export to another file

export const taxTypeArray = [
  {value:  taxType.enum.INCLUSIVE, label: '外税'},
  {value: taxType.enum.EXCLUSIVE, label: '内税'},
]