【问题标题】:Extending theme with material-ui@next and typescript使用 material-ui@next 和 typescript 扩展主题
【发布时间】:2017-12-28 21:52:00
【问题描述】:

在为material-ui 创建主题时,我添加了两个新的调色板选项,可以为我提供更好的明暗范围。我已经扩展了Theme 类型来表明这一点

import {Theme} from "material-ui/styles";
import {Palette} from "material-ui/styles/createPalette";

export interface ExtendedTheme extends Theme {
    palette: ExtendedPalette
}

export interface ExtendedPalette extends Palette {
    light: Color,
    dark: Color,
}

当我尝试在 WithStyles 渲染助手中使用这些附加选项时会出现问题

const styles = (theme : ExtendedTheme) => ({ root: {color: theme.light['100'] }});

export interface MyProps {classes: {[index: string] : string}};
const MyComponent = (props : MyProps) => {...};

// Type ExtendedTheme is not assignable to Theme
export default withStyles(styles : StyleRulesCallback)(MyComponent);

从功能上讲,我的代码在纯 javascript 中运行良好,但由于类型不同,它会引发错误。 material-ui 的类型期望 Theme 类型是样式回调函数的唯一参数:

export type StyleRulesCallback<ClassKey extends string = string> = (theme: Theme) => StyleRules<ClassKey>;

我认为扩展接口将以多态方式工作,以便ExtendedTheme 将实现Theme

【问题讨论】:

    标签: javascript typescript material-ui


    【解决方案1】:

    问题可以使用module augmentation解决:

    declare module '@material-ui/core' {
      interface Theme {
        colors: {
          success: {
            dark: string,
            light: string,
          }
        }
      }
    }
    
    
    

    此外,您可以在 App 组件中声明该模块,并将子组件包装在 ThemeProvider 中:

    import { createMuiTheme, ThemeProvider, colors, ThemeOptions } from '@material-ui/core';
    
    declare module '@material-ui/core' {
      interface Theme {
        colors: {
          success: {
            dark: string,
            light: string,
          }
        }
      }
    }
    
    const App = () => {
      const theme = createMuiTheme({
        colors: {
          success: {
            dark: colors.green[600],
            light: colors.green[300],
          },
        } as ThemeOptions,
      });
    
      return (
        <ThemeProvider theme={theme}>
         <a href="https://material-ui.com/customization/theming/">Theming</a>
        </ThemeProvider>
      )
    

    【讨论】:

    • 请注意,在声明模块的地方应该导入要扩展的接口。 IE。 import { Theme } from "@material-ui/core/styles/createMuiTheme";
    【解决方案2】:

    我想出的唯一答案是让我的自定义选项像这样可选

    export interface ExtendedPalette extends Palette {
        light?: Color,
        dark?: Color,
    }
    

    然后在我的样式回调中,我必须检查这些选项是否存在,这有点麻烦,但我认为没有其他解决方法

    const styles = (theme : ExtendedTheme) => { 
        let light = theme.palette.light[100];
        if(light === undefined) light = theme.common.white;
        { root: {color: light }}
    };
    

    原因是当我使用withStyles 时,主题对象被传递给回调,但是这个回调的类型使用Theme 类型,因为他们无法知道我的ExtendedTheme 类型。当ExtendedTheme 必须有Theme 不知道的选项时,冲突就出现了。通过使这些额外选项可选Theme 仍然可以符合ExtendedTheme。基本上,扩展接口可以传递到期望其父级的地方,但其父级不能传递到期望扩展接口的地方,除非扩展接口以Parent仍然可以遵守的方式扩展。

    一个更简单的例子是有启发性的。

    export interface Foo {foo: string};
    export interface Bar extends Foo {bar: string}
    
    function getFoo(f : Foo) {console.log(f.foo)}
    function getBar(b : Bar) {console.log(b.bar)} 
    function getFooBar(fb: Bar) {console.log(fb.foo, fb.bar)}
    
    const f : Foo = {foo: 'foo'}
    const b : Bar = {foo: 'foo', bar: 'bar'}
    
    getFoo(f) // foo
    getFoo(b) // foo
    getBar(f) // Error Incompatible Type
    getBar(b) // bar
    getFooBar(f) // Error Incompatible Type
    getFooBar(b) // foo bar
    

    getFoo(b) 有效,因为Bar 保证至少拥有Foo 拥有的一切。 getBar(f)getFooBar(f) 都失败了,因为编译器看到类型 Foo 没有键 bar

    像这样重新定义Bar

    export interface Bar extends Foo {bar? : string}
    

    编译器现在知道 Foo 匹配 Bar 类型的最低限定条件,但您必须检查隐式 null。所以这会工作

    getBar(f)
    

    但是编译器会对隐式空值大喊大叫,这很好,因为f.bar 是未定义的。所以你必须像这样重新定义你的功能

    function getBar(b : Bar) {
        let bar = b.bar
        if(bar === undefined) bar = b.foo;
        console.log(bar);
    }
    
    getBar(b) // bar
    getBar(f) // foo
    

    【讨论】:

      猜你喜欢
      • 2020-07-22
      • 2019-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 1970-01-01
      • 2018-02-19
      • 2020-07-20
      相关资源
      最近更新 更多