acdlite/recompose

View on GitHub
src/packages/recompose/index.js.flow

Summary

Maintainability
Test Coverage
/* eslint-disable */

/* @flow strict */

/**
 * 1) Types give additional constraint on a language, recompose was written on the untyped language
 * as a consequence of this fact
 * for some recompose HOCs is near impossible to add correct typings.
 * 2) flow sometimes does not work as expected.
 *
 *  So any help and suggestions will be very appreciated.
 *
 * -----------------------------------------------------------------------------------
 * Type definition of recompose HOCs are splitted into 2 parts,
 * "HOCs with good flow support" - in most cases you can use them without big issues,
 * see `test_${hocName}.js` for the idea.
 * Some known issues:
 * see test_mapProps.js - inference work but type errors are not detected in hocs
 *
 * SUPPORTED HOCs:
 * defaultProps, mapProps, withProps, withStateHandlers, withHandlers, pure,
 * onlyUpdateForKeys, shouldUpdate, renderNothing, renderComponent, branch, withPropsOnChange,
 * onlyUpdateForPropTypes, toClass, withContext, getContext,
 * setStatic, setPropTypes, setDisplayName,
 * -----------------------------------------------------------------------------------
 * "TODO (UNSUPPORTED) HOCs" - you need to provide type information
 * (no automatic type inference), voodoo dancing etc
 * see `test_voodoo.js` for the idea
 *
 * remember that:
 * flattenProp,renameProp, renameProps can easily be replaced with withProps
 * withReducer, withState -> use withStateHandlers instead
 * lifecycle -> you don't need recompose if you need a lifecycle, just use React class instead
 * mapPropsStream -> see test_mapPropsStream.js
 * -----------------------------------------------------------------------------------
 *
 * utils:
 * getDisplayName, wrapDisplayName, shallowEqual,
 * isClassComponent, createSink, componentFromProp,
 * nest, hoistStatics,
 */

//-------------------

// -----------------------------------------------------------------
// Private declarations
// -----------------------------------------------------------------

declare type ExtractToVoid = <A, B, C, R>(
  v: (a: A, b: B, c: C) => R
) => (A, B, C) => void

declare type ExtractStateHandlersCodomain = <State, Enhanced, V>(
  v: (state: State, props: Enhanced) => V
) => V

declare type ExtractHandlersCodomain = <Enhanced, V>(
  v: (props: Enhanced) => V
) => V

declare type UnaryFn<A, R> = (a: A) => R

// -----------------------------------------------------------------
// Public declarations
// -----------------------------------------------------------------

export type Component<A> = React$ComponentType<A>

export type HOC<Base, Enhanced> = UnaryFn<Component<Base>, Component<Enhanced>>

declare export var compose: $Compose

// ---------------------------------------------------------------------------
// ----------------===<<<HOCs with good flow support>>>===--------------------
// ---------------------------------------------------------------------------

declare export function defaultProps<Default, Enhanced>(
  defProps: Default
): HOC<{ ...$Exact<Enhanced>, ...Default }, Enhanced>

declare export function mapProps<Base, Enhanced>(
  propsMapper: (ownerProps: Enhanced) => Base
): HOC<Base, Enhanced>

declare export function withProps<BaseAdd, Enhanced>(
  propsMapper: ((ownerProps: Enhanced) => BaseAdd) | BaseAdd
): HOC<{ ...$Exact<Enhanced>, ...BaseAdd }, Enhanced>

declare export function withStateHandlers<
  State,
  Enhanced,
  StateHandlers: {
    [key: string]: (
      state: State,
      props: Enhanced
    ) => (...payload: any[]) => $Shape<State>,
  }
>(
  initialState: ((props: Enhanced) => State) | State,
  stateUpdaters: StateHandlers
): HOC<
  {
    ...$Exact<Enhanced>,
    ...$Exact<State>,
    ...$ObjMap<
      $ObjMap<StateHandlers, ExtractStateHandlersCodomain>,
      ExtractToVoid
    >,
  },
  Enhanced
>

declare export function withHandlers<
  Enhanced,
  Handlers:
    | ((
        props: Enhanced
      ) => {
        [key: string]: (props: Enhanced) => Function,
      })
    | {
        [key: string]: (props: Enhanced) => Function,
      }
>(
  handlers: ((props: Enhanced) => Handlers) | Handlers
): HOC<
  {
    ...$Exact<Enhanced>,
    ...$ObjMap<Handlers, ExtractHandlersCodomain>,
  },
  Enhanced
>

declare export function pure<A>(a: Component<A>): Component<A>
declare export function onlyUpdateForPropTypes<A>(a: Component<A>): Component<A>
declare export function onlyUpdateForKeys<A>(Array<$Keys<A>>): HOC<A, A>
declare export function shouldUpdate<A>(
  (props: A, nextProps: A) => boolean
): HOC<A, A>

declare export function toClass<A>(a: Component<A>): Component<A>

declare export function withContext<A, ContextPropTypes, ContextObj>(
  childContextTypes: ContextPropTypes,
  getChildContext: (props: A) => ContextObj
): HOC<A, A>

declare export function getContext<CtxTypes, Enhanced>(
  contextTypes: CtxTypes
): HOC<{ ...$Exact<Enhanced>, ...CtxTypes }, Enhanced>

/**
 * It's wrong declaration but having that renderNothing and renderComponent are somehow useless
 * outside branch enhancer, we just give it an id type
 * so common way of using branch like
 * `branch(testFn, renderNothing | renderComponent(Comp))` will work as expected.
 * Tests are placed at test_branch.
 */
declare export function renderNothing<A>(C: Component<A>): Component<A>
declare export function renderComponent<A>(a: Component<A>): HOC<A, A>

/**
 * We make an assumtion that left and right have the same type if exists
 */
declare export function branch<Base, Enhanced>(
  testFn: (props: Enhanced) => boolean,
  // not a HOC because of inference problems, this works but HOC<Base, Enhanced> is not
  left: (Component<Base>) => Component<Enhanced>,
  // I never use right part and it can be a problem with inference as should be same type as left
  right?: (Component<Base>) => Component<Enhanced>
): HOC<Base, Enhanced>

// test_statics
declare export function setStatic<A>(key: string, value: any): HOC<A, A>
declare export function setPropTypes<A>(propTypes: Object): HOC<A, A>
declare export function setDisplayName<A>(displayName: string): HOC<A, A>

declare export function withPropsOnChange<BaseAdd, Enhanced>(
  shouldMapOrKeys:
    | ((props: Enhanced, nextProps: Enhanced) => boolean)
    | Array<$Keys<Enhanced>>,
  propsMapper: (ownerProps: Enhanced) => BaseAdd
): HOC<{ ...$Exact<Enhanced>, ...BaseAdd }, Enhanced>

// ---------------------------------------------------------------------------
// ----------------===<<<TODO (UNSUPPORTED) HOCs>>>===------------------------
// ---------------------------------------------------------------------------

// use withProps instead
declare export function flattenProp<Base, Enhanced>(
  propName: $Keys<Enhanced>
): HOC<Base, Enhanced>

// use withProps instead
declare export function renameProp<Base, Enhanced>(
  oldName: $Keys<Enhanced>,
  newName: $Keys<Base>
): HOC<Base, Enhanced>

// use withProps instead
declare export function renameProps<Base, Enhanced>(nameMap: {
  [key: $Keys<Enhanced>]: $Keys<Base>,
}): HOC<Base, Enhanced>

// use withStateHandlers instead
declare export function withState<Base, Enhanced, T>(
  stateName: string,
  stateUpdaterName: string,
  initialState: T | ((props: Enhanced) => T)
): HOC<Base, Enhanced>

// use withStateHandlers instead
declare export function withReducer<A, B, Action, State>(
  stateName: string,
  dispatchName: string,
  reducer: (state: State, action: Action) => State,
  initialState: State
): HOC<A, B>

// lifecycle use React instead
declare export function lifecycle<A, B>(spec: Object): HOC<A, B>

// Help needed, as explicitly providing the type
// errors not detected, see TODO at test_mapPropsStream.js
declare export function mapPropsStream<Base, Enhanced>(
  (props$: any) => any
): HOC<Base, Enhanced>

// ---------------------------------------------------------------------------
// -----------------------------===<<<Utils>>>===-----------------------------
// ---------------------------------------------------------------------------

declare export function getDisplayName<A>(C: Component<A>): string

declare export function wrapDisplayName<A>(
  C: Component<A>,
  wrapperName: string
): string

declare export function shallowEqual(objA: mixed, objB: mixed): boolean

declare export function isClassComponent(value: any): boolean

declare export function createSink<A>(
  callback: (props: A) => void
): Component<A>

declare export function componentFromProp<A>(propName: string): Component<A>

declare export function nest<A>(
  ...Components: Array<Component<any> | string>
): Component<A>

declare export function hoistStatics<A, B, H: HOC<A, B>>(hoc: H): H

declare export function componentFromStream<T>(
  (props$: any) => any
): T => React$Element<any>

declare export function createEventHandler(): {
  stream: any,
  handler: Function,
}

declare export function toRenderProps<B, E>(
  hoc: HOC<B, E>
): React$ComponentType<{|
  ...$Exact<E>,
  children: (b: B) => React$Node,
|}>

declare export function fromRenderProps<B, E, RenderPropName, Props>(
  RenderPropsComponent: Component<{
    [RenderPropName]: (...props: Props) => React$Node,
  }>,
  propsMapper: ((...props: Props) => B),
  renderPropName?: RenderPropName
): HOC<{ ...$Exact<E>, ...B }, E>