Skip to content

Instantly share code, notes, and snippets.

@gcanti
Created September 14, 2016 09:24
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gcanti/ec95432dc76afc1b457c1b4a44396c09 to your computer and use it in GitHub Desktop.
Save gcanti/ec95432dc76afc1b457c1b4a44396c09 to your computer and use it in GitHub Desktop.
/* @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