Skip to content

Commit

Permalink
[styles] Overload function signature instead of conditional
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Jan 20, 2020
1 parent 335b34e commit 7e72feb
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 114 deletions.
36 changes: 8 additions & 28 deletions packages/material-ui-styles/src/makeStyles/makeStyles.d.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
import {
ClassKeyOfStyles,
ClassNameMap,
PropsOfStyles,
Styles,
WithStylesOptions,
} from '@material-ui/styles/withStyles';
import { Omit, IsAny, Or, IsEmptyInterface } from '@material-ui/types';
import { Omit } from '@material-ui/types';
import { DefaultTheme } from '../defaultTheme';

/**
* @internal
*
* If a style callback is given with `theme => stylesOfTheme` then typescript
* infers `Props` to `any`.
* If a static object is given with { ...members } then typescript infers `Props`
* to `{}`.
*
* So we require no props in `useStyles` if `Props` in `makeStyles(styles)` is
* inferred to either `any` or `{}`
* `makeStyles` where the passed `styles` do not depend on props
*/
export type StylesRequireProps<S> = Or<
IsAny<PropsOfStyles<S>>,
IsEmptyInterface<PropsOfStyles<S>>
> extends true
? false
: true;

export default function makeStyles<Theme = DefaultTheme, ClassKey extends string = string>(
style: Styles<Theme, {}, ClassKey>,
options?: Omit<WithStylesOptions<Theme>, 'withTheme'>,
): (props?: any) => ClassNameMap<ClassKey>;
/**
* @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
* `makeStyles` where the passed `styles` do depend on props
*/
export type StylesHook<S extends Styles<any, any>> = StylesRequireProps<S> extends false
? (props?: any) => ClassNameMap<ClassKeyOfStyles<S>>
: (props: PropsOfStyles<S>) => ClassNameMap<ClassKeyOfStyles<S>>;

export default function makeStyles<
Theme = DefaultTheme,
Props extends {} = {},
ClassKey extends string = string
>(
styles: Styles<Theme, Props, ClassKey>,
options?: Omit<WithStylesOptions<Theme>, 'withTheme'>,
): StylesHook<Styles<Theme, Props, ClassKey>>;
): (props: Props) => ClassNameMap<ClassKey>;
42 changes: 0 additions & 42 deletions packages/material-ui-styles/test/IsEmptyInterface.spec.ts

This file was deleted.

38 changes: 0 additions & 38 deletions packages/material-ui-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,41 +44,3 @@ export type Omit<T, K extends keyof any> = T extends any ? Pick<T, Exclude<keyof
* @internal
*/
export type Overwrite<T, U> = Omit<T, keyof U> & U;

/**
* Returns true if T is any, otherwise false
*/
// https://stackoverflow.com/a/49928360/3406963 without generic branch types
export type IsAny<T> = 0 extends (1 & T) ? true : false;

export type Or<A, B, C = false> = A extends true
? true
: B extends true
? true
: C extends true
? true
: false;

export type And<A, B, C = true> = A extends true
? B extends true
? C extends true
? true
: false
: false
: false;

/**
* @internal
*
* check if a type is `{}`
*
* 1. false if the given type has any members
* 2. false if the type is `object` which is the only other type with no members
* {} is a top type so e.g. `string extends {}` but not `string extends object`
* 3. false if the given type is `unknown`
*/
export type IsEmptyInterface<T> = And<
keyof T extends never ? true : false,
string extends T ? true : false,
unknown extends T ? false : true
>;
2 changes: 1 addition & 1 deletion packages/material-ui/src/styles/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export {
} from './createPalette';
export { default as createStyles } from './createStyles';
export { TypographyStyle } from './createTypography';
export { default as makeStyles, StylesHook } from './makeStyles';
export { default as makeStyles } from './makeStyles';
export { default as responsiveFontSizes } from './responsiveFontSizes';
export { ComponentsPropsList } from './props';
export * from './transitions';
Expand Down
18 changes: 13 additions & 5 deletions packages/material-ui/src/styles/makeStyles.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Theme as DefaultTheme } from './createMuiTheme';
import { Styles, WithStylesOptions } from '@material-ui/styles/withStyles';
import { StylesHook } from '@material-ui/styles/makeStyles';
import { ClassNameMap, Styles, WithStylesOptions } from '@material-ui/styles/withStyles';

import { Omit } from '@material-ui/types';

/**
* `makeStyles` where the passed `styles` do not depend on props
*/
export default function makeStyles<Theme = DefaultTheme, ClassKey extends string = string>(
style: Styles<Theme, {}, ClassKey>,
options?: Omit<WithStylesOptions<Theme>, 'withTheme'>,
): (props?: any) => ClassNameMap<ClassKey>;
/**
* `makeStyles` where the passed `styles` do depend on props
*/
export default function makeStyles<
Theme = DefaultTheme,
Props extends {} = {},
ClassKey extends string = string
>(
styles: Styles<Theme, Props, ClassKey>,
options?: Omit<WithStylesOptions<Theme>, 'withTheme'>,
): StylesHook<Styles<Theme, Props, ClassKey>>;

export { StylesHook };
): (props: Props) => ClassNameMap<ClassKey>;

0 comments on commit 7e72feb

Please sign in to comment.