I would like to share with you our latest iteration of improved withStyles and typescript.
We think it's really awesome.
I believe that after we find a good naming for the methods we can make a PR :)
There's hardcoded { withTheme: true }. but i will change that if there will be a need to something with type overloading or so
import { StyleRulesCallback, Theme, WithStyles, createStyles } from "@material-ui/core";
export type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
import withStyles from "@material-ui/core/styles/withStyles";
import React from "react";
// a wrapper around withStyles that only changes the types
export function createStylesInjector<ClassKey extends string>(
jssStyles: StyleRulesCallback<ClassKey>,
): (<TP extends { classes: (WithStyles<ClassKey>)["classes"]; theme: (WithStyles<ClassKey>)["theme"] }>(
InputComponent: React.ComponentClass<TP> | React.StatelessComponent<TP>,
) => React.ComponentType<Omit<TP, "classes" | "theme">>) & { Type: WithStyles<ClassKey> & { theme: Theme } } {
return withStyles(jssStyles, { withTheme: true }) as any;
}
export interface IStyledComponentProps<T extends { classes: any; theme: any }> {
classes: T["classes"];
theme: T["theme"];
}
const stylesDeclerations = function(theme: Theme) {
return createStyles({
body: {
textAlign: "center",
},
headline: {
textAlign: "left",
},
});
};
const stylesInjector = createStylesInjector(stylesDeclerations);
interface IProps extends IStyledComponentProps<typeof stylesInjector.Type> {
title: string;
caption: number;
}
class MyComponent extends React.Component<IProps, {}> {
public render() {
const { title, caption, theme, classes } = this.props;
return (
<div>
<h1 className={classes.headline}>{title}</h1>
<article className={classes.body}>{caption}</article>
</div>
);
}
}
@oliviertassinari i hope to start discussion about it :)
@Bnaya Thanks for sharing your work! But I'm not really involved in the TypeScript story. Could you check that out with Tom? :)
Hey @pelotom, dose it look like something you would want to include as part of the library?
@Bnaya could you summarize the main innovation here? It seems like some of what you're proposing is already handled fine by the core typings. For example you can just write this
const stylesDeclerations = (theme: Theme) => createStyles({
body: {
textAlign: "center",
},
headline: {
textAlign: "left",
},
});
const stylesInjector = withStyles(stylesDeclerations);
interface IProps extends WithStyles<typeof stylesDeclerations> {
title: string;
caption: number;
}
and the only difference is that theme is considered possibly undefined from within your component. Is that the main thing that you're trying to fix here?
OK, WithStyles looks cool!
My wrapper function is also removing the outside props classes and theme,
And also with overloading we can make the theme exists or not by the value of withTheme
I'll try to make an example later today
We could definitely use types which accurately model when the theme should be available!
@pelotom please take a look at
https://github.com/mui-org/material-ui/pull/12106/files
I hope the test file makes it clear
I think a better solution will be:
// types
type ClassesType<S extends (...args: any[]) => any, T extends ReturnType<S>> = {
[P in keyof T]: string
};
interface WithStyles<T extends (...args: any[]) => any> {
classes: ClassesType<T, ReturnType<T>>;
}
// example of use
const styles = (theme: Theme) =>
createStyles({
root: {
display: "flex",
flexDirection: "column",
flex: 1
},
center: {
alignItems: "center"
}
});
export interface IProps extends WithStyles<typeof styles> {
otherProp: boolean;
}
const Component = ({ otherProp, classes, ...props }: IProps) => {
...
// here classes.root & classes.center will be only options
}
this will automatically add all the styles as string. What do you guys think ?
@ghalex I think the original issue is resolved. So if you have any more issues with the latest version please open a separate issue. Have you checked out https://material-ui.com/guides/typescript/?
Most helpful comment
@Bnaya could you summarize the main innovation here? It seems like some of what you're proposing is already handled fine by the core typings. For example you can just write this
and the only difference is that
themeis considered possiblyundefinedfrom within your component. Is that the main thing that you're trying to fix here?