在我看来 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"));