Harshad Vekariya
Harshad Vekariya

Reputation: 1052

Typescript Module augmentation is not working: Property 'main' does not exist on type 'PaletteColorOptions'

I have been working on Material-UI and trying to use a color system throughout the palette. There seems to be some issue while compilation although it works perfectly in run time. Can someone help me resolve following error:

Error:

Property 'main' does not exist on type 'PaletteColorOptions'.
Property 'main' does not exist on type 'Partial'.(2339)

Here is stackblitz as well: https://stackblitz.com/edit/react-up6bjl-hx1bbh?file=demo.tsx

Code:

import * as React from 'react';
import {
  createTheme,
  Theme,
  ThemeProvider,
  PaletteOptions
} from '@material-ui/core/styles';

import Button from '@material-ui/core/Button';

declare module '@material-ui/core/styles' {
  interface SimplePaletteColorOptions {
    lighter?: string;
    darker?: string;
  }

  interface PaletteColor {
    lighter?: string;
    darker?: string;
  }
}

const Default = () : PaletteOptions => {

  return {
    primary: {
      lighter: '#ddd',
      light: '#ddd',
      main: '#ddd',
      dark: '#ddd',
      darker: '#ddd'
    },
  };
};

export default function CustomColor() {
  const defaultColors = Default();
  
  const palette: PaletteOptions = {
    ...defaultColors,
    divider: defaultColors.primary?.main, // error in compile. Cannot find 'main'
  };

  const theme: Theme = createTheme({
    palette
  });

  console.log(theme.palette.primary.light);

  return (
    <ThemeProvider theme={theme}>
      <Button color="primary" variant="contained">
        neutral
      </Button>
    </ThemeProvider>
  );
}

Upvotes: 8

Views: 8981

Answers (2)

Arajay
Arajay

Reputation: 623

To make custom palette colors work with MUI components (i.e. <Button color={'neutral'}> you also need to augment that component module:

declare module '@mui/material/Button' {
  interface ButtonPropsColorOverrides {
    neutral: true;
  }
}

However, I still had some trouble with Property 'main' does not exist when using the custom theme value in non-MUI components. I solved this by assigning the custom color to its own typed const and then assigning .main to a string explicitly:

const selector: PaletteColor | undefined = theme.palette[color as keyof Palette] as PaletteColor;
const colorString: string = selector ? selector.main : 'inherit';

https://mui.com/material-ui/customization/palette/#non-palette-colors

Upvotes: 0

Ryan Cogswell
Ryan Cogswell

Reputation: 81156

The TypeScript error is unrelated to your module augmentation. The issue is just that defaultColors is of type PaletteOptions. PaletteOptions defines primary to be of type PaletteColorOptions.

Here's the definition of PaletteColorOptions and the types it is built from:

export type PaletteColorOptions = SimplePaletteColorOptions | ColorPartial;

export interface SimplePaletteColorOptions {
  light?: string;
  main: string;
  dark?: string;
  contrastText?: string;
}

export type ColorPartial = Partial<Color>;

export interface Color {
  50: string;
  100: string;
  200: string;
  300: string;
  400: string;
  500: string;
  600: string;
  700: string;
  800: string;
  900: string;
  A100: string;
  A200: string;
  A400: string;
  A700: string;
}

So the TypeScript compiler knows that defaultColors.primary is either SimplePaletteColorOptions or ColorPartial, but it doesn't know which. You are then referencing defaultColors.primary.main, but that isn't guaranteed to be present unless the type of defaultColors.primary is SimplePaletteColorOptions.

You can fix this by using a more specific return type for the Default function that lets TypeScript know that the type of primary is SimplePaletteColorOptions:

interface DefaultPaletteOptions extends PaletteOptions {
  primary?: SimplePaletteColorOptions;
}
const Default = (): DefaultPaletteOptions => {
  return {
    primary: {
      lighter: "#ddd",
      light: "#ddd",
      main: "#ddd",
      dark: "#ddd",
      darker: "#ddd"
    }
  };
};

Edit TypeScript PaletteOptions

Related answers:

Upvotes: 11

Related Questions