-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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] Constrain props type param appropriately in withStyles, withTheme, withWidth HOCs #11003
[typescript] Constrain props type param appropriately in withStyles, withTheme, withWidth HOCs #11003
Changes from 6 commits
e1f809d
f488adf
3560ac0
8eb517a
175fa49
92bee1b
c01d787
89d2a60
bcbf701
9fbbbc1
e66b8ea
0b47fb3
748af39
b24250b
ac934c1
f1dbf16
ea20df9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
import * as React from 'react'; | ||
import { WithTheme } from '../styles/withTheme'; | ||
import { Omit } from '..'; | ||
import { Theme } from './createMuiTheme'; | ||
|
||
/** | ||
|
@@ -28,19 +30,35 @@ export interface WithStylesOptions { | |
|
||
export type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>; | ||
|
||
export interface WithStyles<ClassKey extends string = string> { | ||
export interface WithStyles<ClassKey extends string = string> extends Partial<WithTheme> { | ||
classes: ClassNameMap<ClassKey>; | ||
theme?: Theme; | ||
} | ||
|
||
export interface StyledComponentProps<ClassKey extends string = string> { | ||
classes?: Partial<ClassNameMap<ClassKey>>; | ||
innerRef?: React.Ref<any>; | ||
} | ||
|
||
/* | ||
The Omit<P, 'classes'> below (rather than the canonical Omit<P, WithStyles<ClassKey>>) | ||
is used to allow interoperability with withTheme, which may provide the 'theme' prop. | ||
*/ | ||
/* | ||
export default function withStyles<ClassKey extends string>( | ||
style: StyleRules<ClassKey> | StyleRulesCallback<ClassKey>, | ||
options?: WithStylesOptions, | ||
): <P extends WithStyles<ClassKey>>( | ||
component: React.ComponentType<P>, | ||
) => React.ComponentType<Omit<P, 'classes'> & StyledComponentProps<ClassKey>>; | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's get rid of this instead of commenting out. |
||
|
||
interface MaybeWithStyles<ClassKey extends string> extends Partial<WithStyles<ClassKey>> { | ||
[k: string]: any; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about making a reusable version of this, type ConsistentWith<O> = Partial<O> & Record<string, any>; which can then be used for P extends ConsistentWith<WithStyles<ClassKey>>
P extends ConsistentWith<WithWidthProps>
P extends ConsistentWith<WithTheme> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing semicolon |
||
|
||
export default function withStyles<ClassKey extends string>( | ||
style: StyleRules<ClassKey> | StyleRulesCallback<ClassKey>, | ||
options?: WithStylesOptions, | ||
): <P>( | ||
): <P extends MaybeWithStyles<ClassKey>>( | ||
component: React.ComponentType<P & WithStyles<ClassKey>>, | ||
) => React.ComponentType<P & StyledComponentProps<ClassKey>>; | ||
) => React.ComponentType<Omit<P, 'classes'> & StyledComponentProps<ClassKey>>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
import { Theme } from './createMuiTheme'; | ||
import { Omit } from '..'; | ||
|
||
export interface WithTheme { | ||
theme: Theme; | ||
} | ||
|
||
declare const withTheme: () => <P>( | ||
component: React.ComponentType<P & WithTheme>, | ||
) => React.ComponentClass<P>; | ||
declare const withTheme: () => <P extends WithTheme>( | ||
component: React.ComponentType<P>, | ||
) => React.ComponentClass<Omit<P, keyof WithTheme>>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, this shouldn't require |
||
|
||
export default withTheme; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { Breakpoint } from '../styles/createBreakpoints'; | ||
import { Omit } from '..'; | ||
|
||
export interface WithWidthOptions { | ||
resizeInterval: number; | ||
|
@@ -22,6 +23,6 @@ export function isWidthUp( | |
|
||
export default function withWidth( | ||
options?: WithWidthOptions, | ||
): <P>( | ||
component: React.ComponentType<P & WithWidthProps>, | ||
) => React.ComponentClass<P & Partial<WithWidthProps>>; | ||
): <P extends WithWidthProps>( | ||
component: React.ComponentType<P>, | ||
) => React.ComponentClass<Omit<P, keyof WithWidthProps> & Partial<WithWidthProps>>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, this shouldn't require export default function withWidth(
options?: WithWidthOptions,
): <P extends Partial<WithWidthProps> & Record<string, any>>(
component: React.ComponentType<P & WithWidthProps>,
) => React.ComponentClass<Omit<P, keyof WithWidthProps> & Partial<WithWidthProps>>; With all of these HOCs we want to enable this kind of pattern: const Component = withWidth()<{
// shouldn't need to specify width here; it's a given
name: string
}>(({ width, name }) =>
<div style={{ width }}>hello, {name}</div>
); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I wondered about those two, should have hit them. I'll add a couple of tests, too. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's some merit here, but
P
should not be required to included aclasses
prop. Instead it should be required that ifP
does include aclasses
prop, it should have the right type. Something like this:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks great! Let me check it out a bit.