Mike K
Mike K

Reputation: 6481

How to extend Material-UI Theme with Typescript?

Typescript is always complaining about certain properties missing in the palette. My app works just fine if I add //@ts-ignore, but I obviously want to avoid that. I'm new to Typescript and here is what I've tried.

import createMuiTheme, { ThemeOptions, Theme } from '@material-ui/core/styles/createMuiTheme';
import { PaletteOptions } from '@material-ui/core/styles/createPalette';

interface IPaletteOptions extends PaletteOptions {
    chip: {
      color: string,
      expandIcon: {
        background: string,
        color: string,
      },
    },
}
interface ITheme extends Theme {
  palette: IPaletteOptions,
}

const theme: ITheme = createMuiTheme({
  typography: {
    fontWeightMedium: 600,
    fontFamily: ['Open Sans', 'Arial', 'sans-serif'].join(','),
  },
  palette: {
    primary: {
      main: '#43C099',
    },
    secondary: {
      main: '#7AF3CA',
    },
    chip: {
      color: '#C2C3C6',
      expandIcon: {
        background: '#808183',
        color: '#FFFFFF',
      },
    },
  },
} as ThemeOptions);

This throws an error,

Type 'Theme' is not assignable to type 'ITheme'.
  Types of property 'palette' are incompatible.
    Property 'chip' is missing in type 'Palette' but required in type 'IPaletteOptions

This is a confusing error for me, because type I'm not using the type Palette anywhere.

How can I properly extend the palette here?

Upvotes: 20

Views: 34120

Answers (6)

thisismydesign
thisismydesign

Reputation: 25054

This can be solved much easier via Module Augmentation:

MUI v5

material-ui.d.ts

import "@mui/material/styles/createPalette";

declare module "@mui/material/styles/createPalette" {
  export interface PaletteOptions {
    chip: {
      color: string;
      expandIcon: {
        background: string;
        color: string;
      };
    };
  }
}

MUI v4

material-ui.d.ts

import { PaletteOptions } from "@material-ui/core/styles/createPalette";

declare module "@material-ui/core/styles/createPalette" {
  export interface PaletteOptions {
    chip: {
      color: string;
      expandIcon: {
        background: string;
        color: string;
      };
    };
  }
}

Upvotes: 26

Sagar Paul
Sagar Paul

Reputation: 1

import { createTheme, PaletteOptions } from "@mui/material/styles";

interface CustomTheme extends PaletteOptions {
  dark: {
    main: string;
  };
}

const theme = createTheme({
  palette: {
    primary: {
      main: "#393E46",
    },
    secondary: {
      main: "#00ADB5",
    },
    dark: {
      main: "#222831",
    },
    light: {
      main: "#EEEEEE",
    },
  },
} as {
  palette: CustomTheme;
});

export default theme;

Upvotes: -1

Tarkeasy
Tarkeasy

Reputation: 33

This is for MUI v5

// material-ui.d.ts
import {
  PaletteOptions,
  PaletteColorOptions,
  Palette,
  SimplePaletteColorOptions,
  ColorPartial,
} from '@mui/material/styles/createPalette'

declare module '@mui/material/styles/createPalette' {
  export interface PaletteOptions {
    customRgba?: PaletteColorOptions
  }
  export interface Palette {
    customRgba: SimplePaletteColorOptions & ColorPartial
  }
}

Upvotes: 1

Md. A. Apu
Md. A. Apu

Reputation: 1248

This is how i'm extending in MUI v5

import { PaletteColorOptions } from '@mui/material';

declare module '@mui/material/styles' {

  // add inside palette
  interface PaletteOptions {
    customStatus: PaletteColorOptions;
    colorDark: PaletteColorOptions;
    customDanger: PaletteColorOptions;
  }

  // customize inside palette.background
  interface TypeBackground {
    light: string;
  }

  // add inside theme
  // interface ThemeOptions {
  // }

}

// extend typography inside the theme
declare module '@mui/material/styles/createTypography' {
  interface FontStyle {
    font1: string;
  }
}

Upvotes: 0

jmariano
jmariano

Reputation: 11

In React typescript, you have to declare that the variable is a type of ThemeOptions when using the theme in the child component.

import { ThemeOptions } from '@mui/material';

const ChildComponent: React.FC<Props> = (Props) => {
const theme:ThemeOptions  = useTheme();
  const theme:ThemeOptions = React.useContext(ThemeContext); 
return ()}

Upvotes: 0

keikai
keikai

Reputation: 15146

Solution

import createMuiTheme, { Theme, ThemeOptions } from "@material-ui/core/styles/createMuiTheme";
import { Palette } from "@material-ui/core/styles/createPalette";

interface IPalette extends Palette {
  xxx: {}
}
interface ITheme extends Theme {
  palette: IPalette;
}
interface IThemeOptions extends ThemeOptions {
  palette: IPalette;
}

const theme = createMuiTheme({
  palette: {
    ...
    xxx: {}                                        // Type been checked
  }
} as IThemeOptions)                                // Use customized ThemeOptions type

const useStyles = makeStyles((theme: ITheme) => ({ // Use customized Theme type
  root: {
    color: theme.palette.xxx                       // Work with no type error
  }
}));

Refer

If we look at the createMuiTheme.d.ts

import { Palette, PaletteOptions } from './createPalette';

export interface ThemeOptions {
  palette?: PaletteOptions;
  ...
}

export interface Theme {
  palette: Palette;
  ...
}

export default function createMuiTheme(options?: ThemeOptions, ...args: object[]): Theme;

We would find that Theme and ThemeOptions play a different role.

  • Theme: return type
  • ThemeOptions: params type

Upvotes: 11

Related Questions