From 7a9a332851c1e39703365c0c3ea02948c06d2961 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Wed, 5 Dec 2018 12:35:32 +0100 Subject: [PATCH] [styles] Infer optional props argument for makeStyles in TypeScript --- packages/material-ui-styles/src/index.d.ts | 19 +++++++++++++++++-- .../material-ui-styles/test/index.spec.tsx | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/material-ui-styles/src/index.d.ts b/packages/material-ui-styles/src/index.d.ts index 64b0ddfafbd9f0..4e4a2b9f09a574 100644 --- a/packages/material-ui-styles/src/index.d.ts +++ b/packages/material-ui-styles/src/index.d.ts @@ -111,10 +111,24 @@ declare module '@material-ui/styles/makeStyles' { WithStylesOptions, } from '@material-ui/styles/withStyles'; + // https://stackoverflow.com/a/49928360/3406963 without generic branch types + type IsAny = 0 extends (1 & T) ? true : false; + + /** + * @internal + * + * `Props` are `any` either by explicit annotation or if there are no callbacks + * from which the typechecker could infer a type so it falls back to `any`. + * See the test cases for examples and implications of explicit `any` annotation + */ + export type StylesHook> = IsAny> extends true + ? (props?: any) => ClassNameMap> + : (props: PropsOfStyles) => ClassNameMap>; + export default function makeStyles>( styles: S, options?: WithStylesOptions>, - ): (props: PropsOfStyles) => ClassNameMap>; + ): StylesHook; } declare module '@material-ui/styles/styled' { @@ -200,9 +214,10 @@ declare module '@material-ui/styles/withStyles' { * @internal * This is basically the API of JSS. It defines a Map, * where - * * - the `keys` are the class (names) that will be created * - the `values` are objects that represent CSS rules (`React.CSSProperties`). + * + * if only `CSSProperties` are matched `Props` are inferred to `any` */ export type StyleRules = Record< ClassKey, diff --git a/packages/material-ui-styles/test/index.spec.tsx b/packages/material-ui-styles/test/index.spec.tsx index 1012e985329a62..e10ad30ade66b2 100644 --- a/packages/material-ui-styles/test/index.spec.tsx +++ b/packages/material-ui-styles/test/index.spec.tsx @@ -119,7 +119,23 @@ function testGetThemeProps(theme: Theme, props: AppBarProps): void { ); const NoPropsComponent = () => { const classes = useWithoutProps(); - const alssoClasses = useWithoutProps({}); + const alsoClasses = useWithoutProps(5); + }; + + // unsafe any props make the param optional + const useUnsafeProps = makeStyles( + createStyles({ + root: (props: any) => ({ + backgroundColor: props.deep.color, + }), + }), + ); + + const UnsafeProps = (props: StyleProps) => { + // would be nice to have at least a compile time error because we forgot the argument + const classes = useUnsafeProps(); // runtime: Can't read property color of undefined + // but this would pass anyway + const alsoClasses = useUnsafeProps(undefined); // runtime: Can't read property color of undefined }; }