Home > Enterprise >  TypeScript strictly typed keys in a partial object
TypeScript strictly typed keys in a partial object

Time:01-13

I'm using Mui components with TypeScript and trying to build a helper function to generate extended variants.

import { ButtonProps, ButtonPropsSizeOverrides } from "@mui/material";

declare module "@mui/material/Button" {

  interface ButtonPropsVariantOverrides {
    light: true;
  }

}

type ButtonVariant = ButtonProps["variant"];

const buttonVariants: readonly Exclude<ButtonVariant, undefined>[] = [
  "contained",
  "outlined",
  "light",
  "text",
] as const;

I have actually had this working for a while using a key: string value for the object it returns:

const makeVariants = (): { [key: string]: () => void } => {
  return {
    light: () => {},
  };
};

But I found a typo in one place, and that made me realize I should make this type-safe — instead of string (effectively any string as a key), I should require that the key be a member of the buttonVariants.

I naively tried this:

type VariantMakerKey = typeof buttonVariants[number];

const makeVariants = (): { [key in VariantMakerKey]: () => void } => {
  return {
    light: () => {},
  };
};

But TypeScript is mad because I didn't return all the properties.

// Type '{ light: () => void; }' is missing the following properties from type 
// '{ text: () => void; 
//    outlined: () => void; 
//    contained: () => void; 
//    light: () => void; }': text, outlined, contained

How can I make the object that returns only require a partial set of keys, so that if I define a key, it must be in buttonVariants, but I'm not required to declare them all?

CodePudding user response:

Your mapped type constructs an object type containing all the members of buttonVariants. We have to find a way to make them optional to stop the compiler from requiring all properties to be set.

Their are certain Mapping Modifiers which can change the result of a mapped type. The ? modifier makes all properties optional.

const makeVariants = (): { [key in VariantMakerKey]?: () => void } => {
  return {
    light: () => {},
  };
};

Playground

  • Related