#Create a const string array from a field inside an object array

30 messages · Page 1 of 1 (latest)

sturdy epoch
#

So I have this array of object here:

const tabs = [
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
] as const

And I want to map all value inside this tab variable:

const tabValues = tabs.map(tab => tab.value)

Though, the type result of tabValues is:

("profile" | "inbox" | "settings")[]

instead of:

["profile", "inbox", "settings"]

Is there a way to make it like the above?

I'm trying to put this inside zod.enum, which requires it to be an exact order.

z.enum(tabs.map(tab => tab.value))
dusk cove
#

2 things

#

order doesn't really matter in TS

#

the map function will return an array of element with such types

#

but the actual order should not matter

#

zod.enum, which requires it to be an exact order.
it doesn't

#

you probably misunderstood the error message

#

enums need at lest 1 element

#

they don't care about the order

#

since zod checks one of those elements are present

#

the order in which the possible values are provided doesn't matter

safe condorBOT
#
Ascor8522#7606

Preview:```ts
import {z} from "zod"

const tabs = [
{label: "Profile", value: "profile"},
{label: "Inbox", value: "inbox"},
{label: "Settings", value: "settings"},
] as const

type Value = typeof tabs[number]["value"]

const tabValues = tabs.map(tab => tab.value) as [
Value,
...Value[]
]
...```

dusk cove
#

@sturdy epoch

#

by using as [Value, ...Value[]], you tell TS the array will always have at least 1 element

sturdy epoch
#

@dusk cove wow... that's new to me but works like a charm!

Though, I need to define a type guideline for tabs, so I created this Tab type, so I need to remove the const, and now it becomes just string and breaks zod again.

import { z } from 'zod'

type Tab = {
  label: string
  value: string
}

const tabs: Tab[] = [
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
]

type TabValue = typeof tabs[number]['value']
//   ^? string

z.enum(tabs.map((tab) => tab.value) as [TabValue, ...TabValue[]])

Is there a way to overcome this?

#

I tried to use the new satisfies operator, but seems like it's not allowed:

const tabs = [
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
] satisfies Tab[] as const
A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.ts(1355)
dusk cove
#

you don't need as const if you use satisfies

sturdy epoch
#

Oh, I found a solution now, though it looks really weird and long, are there any alternatives?

const tabs = [
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
] as const satisfies readonly DashboardTab[]
sturdy epoch
dusk cove
#
const tabs = [
  { label: 'Profile', value: 'profile' } as const,
  { label: 'Inbox', value: 'inbox' } as const,
  { label: 'Settings', value: 'settings' } as const,
] satisfies Tab[];

but ugly

sturdy epoch
#

yeah...

is there a way I can create a helper function that will add as const satisfies readonly DashboardTab[] for me?

like:

const tabs = createTabs([
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
])

const createTabs = (tabs: Tab[]) => tabs as const satisfies readonly DashboardTab[]
safe condorBOT
#
Ascor8522#7606

Preview:```ts
import { z } from 'zod'

type Tab = {
label: string
value: string
}

const tabs = [
{ label: 'Profile', value: 'profile' },
{ label: 'Inbox', value: 'inbox' },
{ label: 'Settings', value: 'settings' },
] as const satisfies ReadonlyArray<Tab>;

type TabValue = typeof tabs[number]['value']
...```

dusk cove
#

@sturdy epoch

sturdy epoch
#

I mean like to have

const tabs = createTabs([
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
])

get exact same type of

const tabs = [
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
] as const satisfies ReadyonlyArray<Tab>

the point is that as const satisfies ReadyonlyArray<Tab> is hard to remember, and might be forgotten by teammates.

#
const tabs = createTabs([
  { label: 'Profile', value: 'profile' },
  { label: 'Inbox', value: 'inbox' },
  { label: 'Settings', value: 'settings' },
])

const tabValues = getTabValues(tabs)

z.enum(tabValues)
dusk cove
#

might be forgotten by teammates
that's what code reviews are for

#

well, you wanted extra type narrowing, and that's the price for it

#

but ye, otherwise it will still work, it will just be less precise

sturdy epoch
#

i see... thank you so much!

dusk cove
#

!resolved