import * as React from "react"; import { // Higher-order components mapProps, withProps, withPropsOnChange, withHandlers, defaultProps, renameProp, renameProps, flattenProp, withState, withReducer, branch, renderComponent, renderNothing, shouldUpdate, pure, onlyUpdateForKeys, onlyUpdateForPropTypes, withContext, getContext, lifecycle, toClass, withStateHandlers, // Static property helpers setStatic, setPropTypes, setDisplayName, // Utilities compose, getDisplayName, wrapDisplayName, shallowEqual, isClassComponent, createEagerElement, createEagerFactory, createSink, componentFromProp, nest, hoistStatics, // Observable utilities componentFromStream, mapPropsStream, createEventHandler, createEventHandlerWithConfig, componentFromStreamWithConfig, mapPropsStreamWithConfig, setObservableConfig, StateHandler, StateHandlerMap, } from "recompose"; import rxjsconfig from "recompose/rxjsObservableConfig"; import rxjs4config from "recompose/rxjs4ObservableConfig"; import mostConfig from "recompose/mostObservableConfig"; import xstreamConfig from "recompose/xstreamObservableConfig"; import baconConfig from "recompose/baconObservableConfig"; import kefirConfig from "recompose/kefirObservableConfig"; function testMapProps() { interface InnerProps { inn: number other: string } interface OutterProps { out: string } const InnerComponent = ({inn}: InnerProps) =>
{inn}
; const enhancer = mapProps((props: OutterProps) => ({ inn: 123 })); const Enhanced = enhancer(InnerComponent); const rendered = ( ) } function testWithProps() { interface InnerProps { inn: number } interface OutterProps { out: number } const InnerComponent = ({inn}: InnerProps) =>
{inn}
; const enhancer = withProps((props: OutterProps) => ({ inn: props.out })); const Enhanced = enhancer(InnerComponent); const rendered = ( ) const enhancer2 = withProps({ inn: 123 }); const Enhanced2 = enhancer2(InnerComponent); const Rendered2 = ( ) } function testWithPropsOnChange() { interface InnerProps { inn: number } interface OutterProps { out: number } const InnerComponent = ({inn}: InnerProps) =>
{inn}
; const enhancer = withProps((props: OutterProps) => ({ inn: props.out })); const Enhanced = enhancer(InnerComponent); const rendered = ( ) const enhancer2 = withProps({ inn: 123 }); const Enhanced2 = enhancer2(InnerComponent); const Rendered2 = ( ) } function testWithHandlers() { interface OutterProps { out: number; } interface InnerProps { foo: string; } interface HandlerProps { onSubmit: React.MouseEventHandler; onChange: Function; } const InnerComponent: React.StatelessComponent = ({onChange, onSubmit, foo}) =>
{foo}
; const enhancer = withHandlers({ onChange: (props) => (e: any) => {}, onSubmit: (props) => (e: React.MouseEvent) => {}, }); const Enhanced = enhancer(InnerComponent); const rendered = ( ) const enhancer2 = withHandlers((props) => ({ onChange: (props) => (e: any) => {}, onSubmit: (props) => (e: React.MouseEvent) => {}, })); const Enhanced2 = enhancer2(InnerComponent); const rendered2 = ( ) const handlerNameTypecheckProof = withHandlers({ onChange: () => () => {}, notAKeyOnHandlerProps: () => () => {}, // $ExpectError }); } function testDefaultProps() { interface Props { a: string; b: number; c: number; } const innerComponent = ({a, b}: Props) =>
{a}, {b}
; const enhancer = defaultProps({ a: "answer", b: 42 }); const Enhanced = enhancer(innerComponent); const rendered = ( ) } function testRenameProp() { interface InnerProps { c: string; b: number; } interface OutterProps { a: string; b: number; } const innerComponent: React.StatelessComponent = ({c, b}: InnerProps) =>
{c}, {b}
; const enhancer = renameProp("a", "c"); const enhanced: React.ComponentClass = enhancer(innerComponent); } function testRenameProps() { interface InnerProps { c: string; d: number; } interface OutterProps { a: string; b: number; } const innerComponent: React.StatelessComponent = ({c, d}: InnerProps) =>
{c}, {d}
; const enhancer = renameProps({ a:"c", b: "d" }); const enhanced: React.ComponentClass = enhancer(innerComponent); } function testFlattenProp() { interface InnerProps { a: string; b: string; y: {c: string; d: number;} } interface OutterProps { x: {a: string; b: number;}; y: {c: string; d: number;} } const innerComponent: React.StatelessComponent = (props: InnerProps) =>
; const enhancer = flattenProp("x"); const enhanced: React.ComponentClass = enhancer(innerComponent); } function testWithState() { interface InnerProps { count: number; setCount: (count: number) => number } interface OutterProps { title: string } const InnerComponent: React.StatelessComponent = (props) =>
props.setCount(0)}>
; // We can't infer types for TOutter with this form because // Typescript only allows all or nothing // when defining generics. You can't infer some and define other. // For TOutter to be defined as not "{}" we would have to define // all the generics. const enhancer = withState("count", "setCount", 0); const Enhanced = enhancer(InnerComponent); const rendered = ( ); // Here we're able to infer TOutter since it's defined in the initial state // function and Typescript is able to infer it from there. const enhancer2 = withState("count", "setCount", (p: OutterProps) => p.title.length); const Enhanced2 = enhancer2(InnerComponent); const rendered2 = ( ); } function testWithStateHandlers() { interface State { counter: number; } interface Updaters extends StateHandlerMap { add: StateHandler; } interface OutterProps { initialCounter: number, power: number } type InnerProps = State & Updaters & OutterProps; const InnerComponent: React.StatelessComponent = (props) =>
{`Initial counter: ${props.initialCounter}`}
{`Counter: ${props.counter}`}
props.add(2)}>
; const enhancer = withStateHandlers( (props: OutterProps) => ({ counter: props.initialCounter }), { add: (state, props) => n => ({ ...state, counter: state.counter + n ** props.power }), }, ); const Enhanced = enhancer(InnerComponent); const rendered = ( ); const updateNameTypecheckProof = withStateHandlers( (props: OutterProps) => ({ counter: props.initialCounter }), { notAKeyOfUpdaters: (state, props) => n => ({ ...state, counter: state.counter + n ** props.power }), }, // $ExpectError ); } function testWithReducer() { interface State { count: number } interface Action { type: string } interface InnerProps { title: string; count: number; dispatch: (a: Action) => void; } interface OutterProps { title: string; bar: number; } const InnerComponent: React.StatelessComponent = (props) =>
props.dispatch({type: "INCREMENT"})}>
; // Same issue here inferring TOutter as with the "withState" form. const enhancer = withReducer("count", "dispatch", (s: number, a: Action) => s + 1, 0); const Enhanced = enhancer(InnerComponent); const rendered = ( ); // Here we successfully infer TOutter from the initial state function const enhancer2 = withReducer("count", "dispatch", (s: number, a: Action) => s + 1, (props: OutterProps) => props.title.length); const Enhanced2 = enhancer2(InnerComponent); const rendered2 = ( ); } function testBranch() { interface InnerProps { count: number; update: () => void; } interface OutterProps { toggled: boolean } const innerComponent: React.StatelessComponent = (props: InnerProps) =>
props.update()}>{props.count}
; const innerComponent2 = () =>
Hello
; const enhancer = branch( (props: OutterProps) => props.toggled, withState("count", "update", 0), withState("count", "update", 100) ); const enhancer2 = branch( (props: OutterProps) => props.toggled, renderComponent(innerComponent), ) const enhanced: React.ComponentClass = enhancer(innerComponent); const enhanced2: React.ComponentClass = enhancer2(innerComponent); } function testRenderComponent() { interface InnerProps { count: number; update: () => void; } interface OutterProps { toggled: boolean } const innerComponent = () =>
Hello
; const enhancer = renderComponent(() => Nop!); const enhanced: React.ComponentClass = enhancer(innerComponent); } function testWithObservableConfig() { let componentFromStreamMost = componentFromStreamWithConfig(mostConfig) componentFromStreamMost = componentFromStream let mapPropsStreamMost = mapPropsStreamWithConfig(mostConfig) mapPropsStreamMost = mapPropsStream let createEventHandlerMost = createEventHandlerWithConfig(mostConfig) let { handler: handler, stream: stream } = createEventHandler() createEventHandlerMost = createEventHandler } function testOnlyUpdateForKeys() { interface Props { foo: number; bar: string; } const component: React.StatelessComponent = (props) =>
{props.foo} {props.bar}
onlyUpdateForKeys(['foo'])(component) // This should be a compile error // onlyUpdateForKeys(['fo'])(component) } function testLifecycle() { interface Props { foo: number; bar: string; } interface State {} interface Instance { instanceValue: number } const component: React.StatelessComponent = (props) =>
{props.foo} {props.bar}
lifecycle({ instanceValue: 1, componentDidMount() { this.instanceValue = 2 } })(component) }