타입스크립트 환경에서 MUI 의 테마에 필드를 추가하려면 타입스크립트 또한 추가적인 타입 선언이 필요하다. 어떻게 하면 되는지 유형별로 간단히 살펴보자.

References

1. 테마에 커스텀 필드 추가

테마에 기존에 존재하지 않는 새로운 필드를 추가할 수 있다.

const theme = createTheme({
  status: {
    danger: orange[500],
  },
});

이것을 위한 타입스크립트 타입 선언은 경우에는 아래처럼 해주면 된다.

declare module "@mui/material/styles" {
  interface Theme {
    status: {
      danger: string;
    };
  }
  interface ThemeOptions {
    status?: {
      danger?: string;
    };
  }
}

2. 테마 Palette 에 커스텀 필드 추가

테마의 palatte 에 색상을 추가하면 color, sx prop 등에서 이름만으로 색상을 지정할 수 있게 된다. 아래 코드처럼 palette.neutral을 추가한다면,

const theme = createTheme({
  palette: {
    neutral: {
      main: "#64748B",
      contrastText: "#fff",
    },
  },
});

타입스크립트는 아래처럼 해주면 된다.

declare module "@mui/material/styles" {
  interface Palette {
    neutral: Palette["primary"];
  }
  interface PaletteOptions {
    neutral: PaletteOptions["primary"];
  }
}

이걸로 끝이면 좋겠지만, 특정 컴포넌트의 color 속성에서도 위에서 추가한 색상을 쓰고 싶다면, 해당 컴포넌트에 관한 타입 추가 선언을 해주어야 한다.

// Button 의 color prop 에서 neutral 을 쓰고 싶을 경우
declare module "@mui/material/Button" {
  interface ButtonPropsColorOverrides {
    neutral: true;
  }
}

3. 테마 Palette 의 특정 색상에 필드 추가

Palette 의 특정 색상에 필드를 추가하고 싶을 수 있다. 아래는 palette.primary.darker, palette.background.contrastText 를 추가했다.

const normalTheme = createTheme({
  palette: {
    primary: {
      main: "#0971f1",
      darker: "#053e85",
    },
    background: {
      default: "#E4E7EB",
      contrastText: "#000000",
    },
  },
});

속성을 추가하려는 색상이 primary, secondary, error, warning, info, success 중 하나라면, 이 색상들은 타입을 공유하기 때문에 아래처럼 타입을 지정하면 된다.

declare module "@mui/material/styles" {
  interface PaletteColor {
    darker?: string;
  }
  interface SimplePaletteColorOptions {
    darker?: string;
  }
}

하지만 background 의 경우 다른 타입을 사용하므로 아래처럼 해주어야 한다.

declare module "@mui/material/styles/createPalette" {
  interface TypeBackground {
    default: string;
    paper: string;
    contrastText: string;
  }
}

어떤 색상이 어떤 타입을 사용하는지 알고 싶다면 createPalette.d.ts 코드를 보면 된다. 아래처럼 나와있으니 참고해서 타입 지정을 해주면 된다.

export interface PaletteOptions {
  primary?: PaletteColorOptions;
  secondary?: PaletteColorOptions;
  error?: PaletteColorOptions;
  warning?: PaletteColorOptions;
  info?: PaletteColorOptions;
  success?: PaletteColorOptions;
  mode?: PaletteMode;
  tonalOffset?: PaletteTonalOffset;
  contrastThreshold?: number;
  common?: Partial<CommonColors>;
  grey?: ColorPartial;
  text?: Partial<TypeText>;
  divider?: string;
  action?: Partial<TypeAction>;
  background?: Partial<TypeBackground>;
  getContrastText?: (background: string) => string;
}