通过模块扩展扩展Material UI主题未能正常工作。

6

我正在尝试使用Material UI扩展Theme,但是出现错误,提示我扩展不正确,错误信息如下:

Property 'layout' is missing in type 'Palette' but required in type 'IPaletteOptions'.

以下是我的内容:

// src/theme/theme.d.ts
import { Theme } from "@material-ui/core/styles";
import {
  IPaletteOptions,
  PaletteOptions
} from "@material-ui/core/styles/createPalette";

type TLayout = {
  primary: string;
  secondary: string;
};

declare module "@material-ui/core/styles/createPalette" {
  export interface IPaletteOptions extends PaletteOptions {
    layout: TLayout;
  }
}

declare module "@material-ui/core/styles" {
  export interface ITheme extends Theme {
    palette: IPaletteOptions;
  }
}
// src/theme/index.ts
import { createMuiTheme, ITheme } from "@material-ui/core/styles";
import { IPaletteOptions } from "@material-ui/core/styles/createPalette";

export const palette = {
  layout: {
    primary: "#ffffff",
    secondary: "#e4e4e4"
  }
} as IPaletteOptions;

export default createMuiTheme({ palette }) as ITheme;
// src/App.tsx
import React from "react";
import { ThemeProvider, ITheme } from "@material-ui/core";
import theme from "./theme";

import Component from "./Component";

export default function App() {
  return (
    <ThemeProvider<ITheme> theme={theme}>
      <Component />
    </ThemeProvider>
  );
}
import { useTheme } from "@material-ui/core";
import React from "react";

export default React.memo(() => {
  const theme = useTheme(); // <-- this should be of type `ITheme` automatically
                            // If I do useTheme<ITheme>(), it shows property 'layout', but
                            // I shouldn't have to do that, because of the type casting that
                            // I do in App.tsx, where I import and use 'theme' from src/theme/index.ts

  return <div>the layout primary color is {theme.palette.layout.primary}</div>;
});

我在这里做错了什么?我想在整个应用程序中使用 ITheme,它将扩展基本的Theme以及我添加的内容。

cool-matsumoto-4621h

3个回答

7
在Material v5中,您可以扩展CommonColors
declare module "@mui/material/styles/createPalette" {
  interface CommonColors {
    layout: {
      offBlack: string;
      offWhite: string;
    }
  }
}

const colors = createTheme({
  palette: {
    common: {
      layout: {
        offBlack: "#14142B",
        offWhite: "#FCFCFC",
      },
    },
  },
});

// In a component
const useStyles = makeStyles((theme) => ({
  target: {
    backgroundColor: theme.palette.common.layout.offBlack
  }
}));

你有你的项目链接吗? - aa bb
谢谢你,看到你在declare module "@mui/material/styles/createPalette"中有特殊路径来覆盖这个问题,这非常有帮助。 - Narigo

5

我认为即使是以下使用了你的ITheme的东西,重写起来也会更方便:

theme.d.ts

declare module "@material-ui/core/styles" {
  export interface ITheme extends Theme {
    palette: IPaletteOptions;
  }
  
  // Keep overriding these things in your app
  // In this case returns `ITheme`
  export function createMuiTheme(options?: ThemeOptions, ...args: object[]): ITheme;
  
  // returns `ITheme`
  export function useTheme<T = ITheme>(): T;
}

那么在您的theme/index.ts中,您就不再需要显式地转换返回类型了:

export default createMuiTheme({ palette });

如果使用useTheme,它应该按预期返回ITheme

注意:我也已经更新了codesandbox:https://codesandbox.io/s/charming-pasteur-s6h8v?file=/src/Component.tsx


感谢您的建议。另外,请注意,在您的沙盒中TS仍在抱怨(“接口 'ITheme' 错误地扩展了接口 'Theme'。属性'theme'的类型不兼容。”)。 - Mike K
这是您之前的设置。看起来新类型的 palette IPaletteOptions 与当前的 Theme["palette"] 不完全兼容。但我们可以通过像这样设置来解决问题 export type ITheme = Theme & { palette: IPaletteOptions }。在此处检查新更改:https://codesandbox.io/s/charming-pasteur-s6h8v?file=/typings/theme.d.ts - tmhao2005

0

我通过使用以下方法使其工作:

declare module '@material-ui/styles' {
  export interface DefaultTheme extends CustomTheme {}
}

注意:'core' 模块未被包含在内。

我的完整代码:

import theme from './theme';

type CustomTheme = {
  palette: typeof theme;
};

declare module '@material-ui/styles' {
  export interface DefaultTheme extends CustomTheme {}
}

你有项目链接吗?我想知道你的不同文件是如何组织和调用的。 - aa bb

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