如何使用Typescript扩展Material-UI主题?

18

TypeScript总是抱怨调色板中缺少某些属性。如果我添加//@ts-ignore,我的应用程序就能正常工作,但我显然想避免这样做。我对TypeScript还很陌生,以下是我尝试的内容。

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);

这会抛出一个错误,

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

这个错误让我感到困惑,因为我没有在任何地方使用类型 Palette

我该如何正确地扩展调色板?


这个回答解决了您的问题吗?使用material-ui@next和typescript扩展主题 - Adam Jeliński
6个回答

24
这个问题可以通过模块增强更轻松地解决: 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;
      };
    };
  }
}

这里也可以找到详细的解释: https://medium.com/javascript-in-plain-english/extend-material-ui-theme-in-typescript-a462e207131f - Link
在我的情况下,我不得不使用模块增强、映射类型和常量断言来使我的自定义主题对象与TypeScript配合使用,并提供有用的智能感知:https://dragoshmocrii.com/material-ui-custom-theme-and-typescript/ - Dragos

10

解决方案

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
  }
}));

参考

如果我们查看 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;

我们会发现ThemeThemeOptions扮演不同的角色。

  • Theme: 返回类型
  • ThemeOptions: 参数类型

谢谢您的回答。我有些难以理解,我想扩展调色板(即,我希望它具有原始调色板属性+我的自定义属性)。那么,为什么要使用 interface ITheme extends Theme { palette: Palette }?或者我应该制作自己的 IPalette 并执行 interface ITheme extends Theme { palette: Palette<IPalette> }?因为问题在于 Typescript 告诉我 type Palette 上不存在 chip,所以我应该制作自己的 interface IPalette { chip: { ... } } 吗? - Mike K
@MikeK 已更新。 - keikai

0
在React TypeScript中,在子组件中使用主题时,您必须声明变量是ThemeOptions类型。
import { ThemeOptions } from '@mui/material';

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

1
您的回答目前不太清楚。请进行[编辑]以添加更多细节,帮助其他用户理解如何回答问题。您可以在帮助中心找到有关编写良好答案的更多信息。 - Community

0

这是我在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;
  }
}

0

这是针对 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
  }
}

-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;


你的回答目前写得不够清楚。请编辑并添加更多细节,以帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,