#How to type a Record of button variants (primary, secondary, etc.) without repeating variant names

5 messages · Page 1 of 1 (latest)

bold spoke
#

I find myself frequently building objects like this:

const buttonVariants = {
  primary: {
    color: 'white',
    bgColor: 'green',
  },
  secondary: {
    color: 'white',
    bgColor: 'red',
  }
}

What I want is to define the types of each record without casting the keys into "string" so I can get the names of variants directly from the buttonVariants variable:

type ButtonVariant = keyof typeof buttonVariants

type ButtonDefinition = {
  color: string
  bgColor: string
}

// Type error: type references itself
const buttonVariants: Record<ButtonVariant, ButtonDefinition> = {
  primary: {
    color: 'white',
    bgColor: 'green',
  },
  ...
}

Is this even possible? I get that it's kind of self-referencial, but all I really want to do is get autocomplete for ButtonDefinition when I'm adding new variants to the buttonVariant object, while still being able to extract the names of all the variants I've created so I can use that generated type as the variant prop on my buttons:

type ButtonProps = ComponentProps<'button'> & {
  variant?: ButtonVariant
}

const ButtonComponent = ({ variant = 'primary', ...rest }: ButtonProps) => {
  const { color, bgColor } = buttonVariants[variant]

  ...
}
stuck pollen
#

sounds like satisfies is what you want

turbid ventureBOT
#
that_guy977#0

Preview:```ts
type ButtonVariant = keyof typeof buttonVariants
// ^?

type ButtonDefinition = {
color: string
bgColor: string
}

const buttonVariants = {
// ^?
primary: {
color: 'white',
bgColor: 'green',
},
} satisfies Record<string, ButtonDefinition>```

bold spoke
#

Interesting — hadn’t heard about ‘satisfies’ but it’s been a while since I read the manual. Will need to start keeping up to date 😜 I’ll give that a shot, thanks! 🙏

stuck pollen
#

it's a relatively new feature