-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Typescript] Generic React ClassComponent && withStyles #14544
Comments
That is unfortunately not in our power. Every higher-order component I know so far looses the generic type information. It's hard to explain but HOCs usually take a generic component The only workaround is to override the exported type somehow so that you end up with export class MyGenericComponent<T> extends React.Component<MyOriginalComponentProps<T> & StyledComponentProps<typeof styles>> {}; I'm very interested in how other higher-order components would approach this issue. |
We have the same issue on The only "real" solution is to have another component around the |
I'm happy to improve the typings if somebody knows any higher-order component that doesn't loose generic type information. Until then I fear this is not actionable for us since it's a limitation of typescript. Leaving this open since we should mention this somewhere in our docs. Either link to another resource that describes generic component and hocs or write it ourself. Looking for contributions. |
i use something similar to this for typestyle / csx / mergeStyles and works great. styled components will be restricted to only proper dom props and the additional props you pass in as types You have to use a simple css function though, which I don't know where that lives in the mui library. import React, { HTMLProps } from 'react';
import clsx from 'clsx';
import {hoistStatics} from './hoist';
import {withStyles, WithStyles, makeStyles} from '@material-ui/styles';
import { CSSProperties, Styles } from '@material-ui/styles/withStyles';
const h = React.createElement
type DomProps = Partial<HTMLProps<any>>
type CSX = { css?: CSSProperties , clone?: boolean, children?: React.DetailedHTMLProps<any, any>}
type StyledCSX = DomProps & CSX & Partial<WithStyles<any>>
//type StyledCSX = DomProps & CSX & Partial<WithStyles<any>> & Partial<Styles<any, P>>
type Proptional<P> = Styles<any, P> | ((...args: P[]) => Styles<any, P>)
export function typestyled<P>(C) {
return (...props: Proptional<P>[]) => {
const Comp = (originalProps: P & DomProps) => {
const className = [
originalProps.className,
...props.map(a => typeof a === 'function' ? a(originalProps) : a)
.filter(s => !!s)
.map(s => withStyles<Styles<any, P>, any>(s)) //<-- not gonna work
//.map(s => cssFunction(s)) //<-- replace with something like this, where css function creates only 1 css rule, not stylesheet-like
//style(originalProps.classes || {}), <--pick up original classes here
].join(' ').trim() //u can use clsx here if u want i guess , but dont need to
return h(C, ({className, ...originalProps, props}))
}
return Comp
}
} return (...props: Proptional<P>[]) => { is replacing the current mui impl of const componentCreator = (style, options?) => { and the biggest thing is applying the styles before you return, not returning the withStyles function like you are currently. I tried using makeStyles and doing like an inline hoc type thing but i couldn't get it work :\ that might be a better option though https://github.com/jeremy-coleman/jss/tree/master/src I also was trying to get a working version of jss in typescript up and going and asked for help from jss team but nothing so far - maybe you guys will find it helpful. I think some fixes need to be made, which i mentioned here cssinjs/jss#1053 the stylesheet is the root of the problem - notice the constructor and public 'options' property have different types. also the options.Renderer(this) -- the Renderer there is referencing a type - i don't know how that even works in the first place |
DefinitelyTyped/DefinitelyTyped#37087 addresses the same issue: Generic types are lost with higher-order functions. See microsoft/TypeScript#30650 (comment) for the current conclusion of this issue. Closing this since it's not actionable for us and I'd much rather document the issue in the react-typescript-cheatsheet. |
I haven't come up with a good pattern for the general case (HOCs losing generics), but after some exploration I came up with this workaround that strikes an acceptable (for me) balance of readability, simplicity, flexibility and repetitiveness. It's not ideal, but it's little enough work that I'm willing to take up brainspace for it in exchange for the safety it provides. export type GenericWithStyles<T extends WithStyles<any, any>> =
Omit<T, "theme" | "classes"> &
{ classes?: T["classes"]; } &
("theme" extends keyof T ? { theme?: Theme } : {}); Usage: const styles = (theme: Theme) => createStyles({ ... });
interface Props<T> extends WithStyles<typeof styles, true> {
// ...
}
const MyComponent = withStyles(styles, { withTheme: true })(MyComponentStyled) as
<T>(props: GenericWithStyles<Props<T>>) => React.ReactElement; Note that it requires a function declaration at each usage: you need to provide a type parameter declaration that Typescript can infer/allow you to specify. If you tried to do something like |
@seansfkelley Works in my case. Thanks. |
Hello everyone, can't figure out how to solve this so I'm asking for your help :)
Using typescript + react + material-ui (latest versions at the time of writing, cf package.json in repo, link at the bottom).
Can't share the real code but made a small project to reproduce my problem.
I have a generic class like so:
The aim here is to be able to have typings in the onClick callback function.
(kind of like what apollo-client is doing with Query && Mutation components).
It is used like this:
As you can see, it works fine when I extend the "original" component (not wrapped withStyles).
I get the typing I need in the onClick call prop.
But I can't make it work with the wrapped component (with "withStyles").
I get the error in the comment.
Any idea ? thx :)
PS: here is the repo which reproduce my problem, if you want to run it yourself (create-react-app typescript + material-ui https://github.com/nihaux/typescript-generic-material-ui-withstyle)
The text was updated successfully, but these errors were encountered: