it seems to me the material-ui definition for muiThemeable function is not right ...
doing
export default muiThemeable()(MainHeader);
is the same as doing
export const themed = muiThemeable<MainHeader, {}, {}>()(MainHeader)
and doesn't compile because
you omitted component property type and component property state
the compiler infers
<TComponent<P, S>,{}, {}>
which doesn't match the Function constraints
export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>()
: (component: TComponent ) => TComponent;
... lets add the missing constrains
to satisfy the compiler , we should do
export default (props: Properties) => muiThemeable<MainHeader, Properties, any>()(new MainHeader(props));
but this is giving an instance to the function , when the F is expecting a class
if you later on do ...
// ...
import Themeable from "./themeable";
let props = { title: "hello!" };
ReactDOM.render(<Themeable {...props}/>, document.getElementById("main"));
it won't work
but if you change muiThemeable definition to:
export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>()
: (component: Function ) => TComponent;
then you can use:
export default muiThemeable<MainHeader, Properties, any>()( MainHeader);
the tsc will generate errors
JSX element type 'Themeable' does not have any construct or call signatures
but it will transpile the right thing , and work
but that's not OK,
because:
- it doesn't build
- Function is NOT describing the right parameter type
- neither TComponent describes what is returned,
it looks like its returning an instance when we need a class,... a type
finally:
this signature makes a bit more sense:
export function muiThemeable<TComponent extends (React.Component<P, S>), P, S>(): (component: new()=> TComponent ) => ( new() => TComponent);
but after looking at the source
export function muiThemeable<TComponent extends React.Component<P, S>, P extends MuiThemeProviderProps, S> (Component: new () => TComponent): React.StatelessComponent<P>
And this could be a way to get away with re-writing or augmenting the definition.
Wrapping the function
... and perhaps using a decorator to reduce boilerplate and easier reading...
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"));