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)
}