Created
September 14, 2016 09:24
-
-
Save gcanti/ec95432dc76afc1b457c1b4a44396c09 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* @flow */ | |
import React from 'react' | |
import ReactDOM from 'react-dom' | |
type FunctionComponent<A> = (props: A) => ?React$Element<any>; | |
type ClassComponent<D, A, S> = Class<React$Component<D, A, S>>; | |
type Component<A> = FunctionComponent<A> | ClassComponent<any, A, any>; | |
type Fn1<A, B> = (a: A) => B; | |
type HOC<A, B> = Fn1<Component<A>, Component<B>>; | |
declare function compose<A, B, C, D, E>(de: Fn1<D, E>, cd: Fn1<C, D>, bc: Fn1<B, C>, ab: Fn1<A, B>, ...rest: Array<void>): Fn1<A, E>; | |
declare function compose<A, B, C, D>(cd: Fn1<C, D>, bc: Fn1<B, C>, ab: Fn1<A, B>, ...rest: Array<void>): Fn1<A, D>; // eslint-disable-line no-redeclare | |
declare function compose<A, B, C>(bc: Fn1<B, C>, ab: Fn1<A, B>, ...rest: Array<void>): Fn1<A, C>; // eslint-disable-line no-redeclare | |
export function compose(...fns) { // eslint-disable-line no-redeclare | |
const len = fns.length - 1 | |
return result => { | |
for (let i = len; i > -1; i--) { | |
result = fns[i].call(this, result) | |
} | |
return result | |
} | |
} | |
// Component<A> is a contravariant functor | |
export function contramap<A, B>(f: (a: B) => A): HOC<A, B> { | |
return C => b => <C {...f(b)} /> // eslint-disable-line react/display-name | |
} | |
const getLength = contramap(({ a }: { a: string }) => ({ a, b: a.length })) | |
const defaultBoolean = contramap(({ a, b }: { a: string, b: number }) => ({ a, b, c: true })) | |
const C1: Component<{a: string, b: number, c: boolean}> = props => <div><pre>{JSON.stringify(props, null, 2)}</pre></div> | |
const C2 = defaultBoolean(C1) | |
const C3 = compose(getLength, defaultBoolean)(C1) | |
ReactDOM.render(<C1 a="hello" b={5} c={true} />, document.getElementById('app')) // <= ok | |
// ReactDOM.render(<C2 />, document.getElementById('app')) // <= error: property `a`. Property not found, property `b`. Property not found | |
ReactDOM.render(<C2 a="bye" b={3} />, document.getElementById('app')) // <= ok | |
// ReactDOM.render(<C3 />, document.getElementById('app')) // <= error: property `a`. Property not found | |
ReactDOM.render(<C3 a="ok" />, document.getElementById('app')) // <= ok |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment