2

I have a custom theme with some additional key/values added to the theme. This is causing TS errors when I go to use the design tokens in my app. I know I need to use module augmentation to fix it but honestly I am so confused as to where this goes, or how this would be done properly. I think the docs are really scarce on the topic, and other stackoverflows are just as brief with little context as to why or where they are getting the elements defined within their module augmented themes. The theme I built is below for reference. Thanks in advance, any and all help is appreciated.

The error I'm receiving is a variation of this below for each custom theme property:

Type '{ main: string; secondary: string; nav: { main: string; active: string; inactive: string; }; }' is not assignable to type 'Partial<TypeBackground>'.
  Object literal may only specify known properties, and 'main' does not exist in type 'Partial<TypeBackground>'

My current theme is below:

const muiTheme = createTheme({
  palette: {
    primary: { // orange
      main: '#ff5e3d',
      contrastText: '#e3e8f0'
    },
    secondary: { // black
      main: '#585858',
      contrastText: '#e3e8f0'
    },
    background: {
      //@ts-ignore
      main: '#FFFFFF', //white
      secondary: "#f1f5f9", //lightblue
      nav: {
        main: '#1e293b',
        active: '#0f172a',
        inactive: '#1e293b'
      }
    },
    info: undefined,
    text: {
      primary: "#11142d", 
      secondary: "#fff", 
      //@ts-ignore
      nav: "#64748b", 
      meta: "#94a3b8"
    },
    icons: {
      active: {
        primary: '#ff5e3d',
        secondary: '#ffffff',
      },
      inactive: {
        primary: '#94a3b8',
        secondary: '#475569',
      }
    },
    contrastThreshold: 1,
    tonalOffset: 0.2,
  },
  typography: {
    fontFamily: ['Gotham', 'Mulish', 'Helvetica', 'Arial', 'sans-serif'].join(","),
    h1: {
      fontFamily: "Gotham, Helvetica",
      fontWeight: 700,
      lineHeight: '24px',
      fontSize: '16px',
      textTransform: "uppercase",
    },
    h2: {   
      fontFamily: "Gotham, Helvetica",
      fontWeight: 400,
      lineHeight: '24px',
      fontSize: '16px',
    },
    h3: {
      fontFamily: "Mulish, Arial",
      fontWeight: 700,
      lineHeight: '24px',
      fontSize: '16px',
      textTransform: "uppercase",
    },
    subtitle1: {
      fontFamily: "Gotham, Helvetica",
      fontWeight: 400,
      lineHeight: '19.5px',
      fontSize: '13px',
    },
    body1: {
      fontFamily: "Mulish, Arial",
      fontWeight: 400,
      lineHeight: '21px',
      fontSize: '14px',
    },
    h4: undefined,
    h5: undefined,
    h6: undefined,
    body2: undefined,
    subtitle2: undefined,
    caption: undefined,
  },
  components: {
    MuiCssBaseline: {
      styleOverrides: `${[Gotham, Mulish]}`,
    },
    MuiButton: {
      styleOverrides: {
        root: ({ ownerState, theme }) => ({
          fontFamily: "Mulish, Arial",
          fontWeight: 700,
          lineHeight: '15.6px',
          fontSize: '13px',
          paddingY: 8,
          paddingX: 12,
          //@ts-ignore
          borderColor: theme.palette[ownerState.color].main,
          borderRadius: 22.5,
          borderWidth: 2,
          "&:hover": {
            borderWidth: 2
          }
        }),
      },
    },
    // change other base components here
  },
});

EDIT: I am also receiving a type error indicating that icon does not exist on type Palette. I'm using the useTheme hook in order to fetch the them object so I can get the theme values for an SVG that takes two color props. If active, the colors of the SVG change. This object is passed to the custom icon component and colors deconstructed, it currently works minus the TS error. The code for the active switch where the TS error is, is below:

const isActive = (
  active: boolean,
  theme: Theme,
): {
  background: string;
  iconPrimary: string;
  iconSecondary: string;
} => {
  return active
    ? {
        //@ts-ignore
        iconPrimary: theme.palette.icons.navIcon.active.primary,
        //@ts-ignore
        iconSecondary: theme.palette.icons.navIcon.active.secondary,
      }
    : {
        //@ts-ignore
        iconPrimary: theme.palette.icons.navIcon.inactive.primary,
        //@ts-ignore
        iconSecondary: theme.palette.icons.navIcon.inactive.secondary,
      };
};

1 Answers1

1

Try the following. It should work!

The code below augments the needed interfaces (More about augmentation in the official docs):

declare module "@mui/material" {
  export interface TypeBackground {
    main: string;
    secondary: string;
    nav: {
      main: string;
      active: string;
      inactive: string;
    }
  }

  export interface PaletteOptions {
    icons: {
      active: {
        primary: string;
        secondary: string;
      },
      inactive: {
        primary: string;
        secondary: string;
      },
    }
  }

  export interface TypeText {
    nav: string;
    meta: string;
  }

  export interface Palette {
    icons: PaletteOptions['icons'];
  }
}

The snippets below fix the errors:

          borderColor: ownerState.color && ownerState.color !== 'inherit'
            ? theme.palette[ownerState.color].main
            : undefined,

And:

const isActive = (
  active: boolean,
  theme: Theme,
): {
  background?: string;
  iconPrimary: string;
  iconSecondary: string;
} => {
  return active
    ? {
        iconPrimary: theme.palette.icons.active.primary,
        iconSecondary: theme.palette.icons.active.secondary,
      }
    : {
        iconPrimary: theme.palette.icons.inactive.primary,
        iconSecondary: theme.palette.icons.inactive.secondary,
      };
};
lepsch
  • 8,927
  • 5
  • 24
  • 44
  • thank you let me implement! Also thanks for helping with the last TS error! Nice little bonus :). I'll follow up to let you know how it goes! One last question though, should I put this module declaration in its own `theme.d.ts` file or in the theme definition file? – Salvatore Argentieri Jul 11 '22 at 17:49
  • You can put the module declaration in a separate file or even beside the `muiTheme` declaration it should work. – lepsch Jul 11 '22 at 18:14
  • This worked. Thank you so much! I put it next to the theme file, cause it caused more TS issues with the theme being imported, not sure why. Why couldn't I use optional chaining for the borderColor line? – Salvatore Argentieri Jul 11 '22 at 19:28
  • Also one last thing. I'm referencing the theme elsewhere via the `useTheme` hook, and it throws an error saying icon does not exist on type palette. How can I fix that TS error? – Salvatore Argentieri Jul 11 '22 at 20:31
  • Would you please [edit] your question and add the code snippet where the error occurs? – lepsch Jul 11 '22 at 20:32
  • Hey looks like my message didn't send yesterday. I updated the OG post to include the new error. I cannot thank you enough for your assistance on the matter @lepsch! – Salvatore Argentieri Jul 12 '22 at 16:20
  • I've updated the answer with the fix. Please take a look. – lepsch Jul 12 '22 at 16:50
  • Thank you for your assistance. Do you have any resources that I can refer to for my understanding. I think I understand how it works much better now! – Salvatore Argentieri Jul 13 '22 at 18:39
  • This one is the best I know about augmentation: https://www.typescriptlang.org/docs/handbook/declaration-merging.html – lepsch Jul 13 '22 at 18:43
  • Thanks for all your help and direction, I owe you one! – Salvatore Argentieri Jul 14 '22 at 17:32