【问题标题】:Using Material-UI muiThemeable in Typescript在 Typescript 中使用 Material-UI muiThemeable
【发布时间】:2017-04-30 04:46:53
【问题描述】:

我正在尝试访问自定义 React 组件中的当前主题颜色。我使用的示例来自 Material UI http://www.material-ui.com/#/customization/themes

我尝试了多种变体,但无法让 Typescript 编译我的组件。我得到的错误是... error TS2345: 'typeof MainHeader' 类型的参数不可分配给'Component' 类型的参数。

import * as React from "react";
import muiThemeable from 'material-ui/styles/muiThemeable';

interface Properties  {
  title: string
}

class MainHeader extends React.Component<Properties, any> {

render() {
  return (
    <div className='hero' >
      <div className='logo' />
      <div className="bar" />

      <h1>{this.props.title}</h1>
    </div>
  );
  }
}

export default muiThemeable()(MainHeader);

【问题讨论】:

    标签: reactjs typescript material-ui


    【解决方案1】:

    在我看来 muiThemeable 函数的 material-ui 定义不正确...

    在做

    export default muiThemeable()(MainHeader);
    

    和做的一样

    export const themed = muiThemeable<MainHeader, {}, {}>()(MainHeader)
    

    并且无法编译,因为 你省略了组件属性类型和组件属性状态

    编译器推断

    <TComponent<P, S>,{}, {}>
    

    与函数约束不匹配

            export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>()
                : (component: TComponent ) => TComponent;
    

    ...让我们添加缺少的约束

    为了满足编译器,我们应该这样做

    export default (props: Properties) => muiThemeable<MainHeader, Properties, any>()(new MainHeader(props));
    

    但是当 F 期待一个类时,这是给函数一个实例

    如果你以后做...

    // ...    
    import Themeable from "./themeable";
    let  props = { title: "hello!" };
    ReactDOM.render(<Themeable {...props}/>, document.getElementById("main"));
    

    不会用的

    但如果您将 muiThemeable 定义更改为:

     export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>()
            : (component: Function ) => TComponent;
    

    那么你可以使用:

    export default muiThemeable<MainHeader, Properties, any>()( MainHeader);
    

    tsc 会产生错误

    JSX element type 'Themeable' does not have any construct or call signatures
    

    但它会转换正确的东西,并且可以工作

    但是这样不行,

    因为:

    • 它没有构建
    • 函数未描述正确的参数类型
    • TComponent 都不描述返回的内容,

    当我们需要一个类时,它看起来像返回一个实例,......一个类型

    终于:

    这个签名更有意义:

    export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>(): (component: new()=> TComponent ) => ( new() =>  TComponent);
    

    但是看了source之后

    export function muiThemeable<TComponent extends React.Component<P, S>, P extends MuiThemeProviderProps, S> (Component: new () => TComponent): React.StatelessComponent<P> 
    

    这可能是一种摆脱重写或扩充定义的方法。
    包装函数
    ...也许使用装饰器来减少样板文件并更容易阅读...

        import * as React from "react";
        import * as ReactDOM from "react-dom";
        import * as injectTapEventPlugin from "react-tap-event-plugin";
    
        // Needed for onTouchTap
        // http://stackoverflow.com/a/34015469/988941
        injectTapEventPlugin();
    
    
        import darkBaseTheme from "material-ui/styles/baseThemes/darkBaseTheme";
        import MuiThemeProvider from "material-ui/styles/MuiThemeProvider";
        import getMuiTheme from "material-ui/styles/getMuiTheme";
        import muiThemeable from "material-ui/styles/muiThemeable";
    
        import AppBar from "material-ui/AppBar";
        import MuiThemeProviderProps = __MaterialUI.Styles.MuiThemeProviderProps;
    
        function Themeable<TComponent extends React.Component<P, any>, P extends MuiThemeProviderProps> (Component: new () => TComponent): new() => TComponent {
            return muiThemeable<TComponent, P, any>()(Component as any) as any;
        }
    
        const themeable = <P, TFunction extends React.ComponentClass<P>>(target: TFunction): TFunction => {
            return Themeable(target as any) as any;
        };
    
        export interface MyBarProps extends __MaterialUI.AppBarProps, __MaterialUI.Styles.MuiThemeProviderProps {
            // ...
        }
    
        @themeable
        export class MyBar extends React.Component<MyBarProps, any> {
    
            constructor(props?: MyBarProps, context?: any) {
                super(props, context);
            }
    
            render() {
                if (!this.props.muiTheme) {
                    throw new Error("muiTheme not Found");
                }
                return (
                    <AppBar {...this.props} />
                );
            }
        }
    
        const darkTheme = getMuiTheme(darkBaseTheme);
        darkTheme.appBar.color = "red";
    
        const Main = () => (
            <MuiThemeProvider muiTheme={darkTheme}>
                <MyBar title="My AppBar" />
            </MuiThemeProvider>
        );
    
        ReactDOM.render(<Main></Main>,document.getElementById("root"));
    

    【讨论】:

    • 你是如何在 TypeScript 中使用它的?一直在尝试做与 OP 相同的事情,但似乎找不到解决方案……您能否发布一个完整的示例,说明如何将 muiThemeable 与 TypeScript 一起使用?
    • @RicardoAmaral 请查看this 是否有帮助,只是为了您的方便而上传的 :),buena suerte!
    • 该链接是否旨在准确指向该文件?刚刚克隆了整个项目,但找不到任何对 muiThemeable 的引用...我错过了什么吗?
    • 你是对的,没有,但是如果查看muiThemeable,你会发现它只是从上下文中设置道具,这几乎就是它在 mobx 中的@inject 所做的。抱歉链接,我粘贴了错误的网址。
    • @RicardoAmaral,也许编辑后的答案会有所帮助......?
    猜你喜欢
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    • 2020-07-20
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    相关资源
    最近更新 更多