Skip to content

Expected functionality of $Diff #3396

Open
@echenley

Description

I know there are other issues related to $Diff, but I wanted to lay out a particular use case that would eliminate a lot of the pain of using flow to type higher order functions and React components.

Current Scenario

Currently, flow forces you to manually diff objects, exemplified by the Translator HOC in the libdef for react-i18next:

declare type Translator<OP, P> = {
  (component: StatelessComponent<P>): Class<React$Component<void, OP, void>>;
  <Def, St>(component: Class<React$Component<Def, P, St>>): Class<React$Component<Def, OP, St>>;
}

(this was in modeled after react-redux's Connector, which could probably also benefit from $Diff)

And it's usage:

type Props = { a: string }
type PropsWithT = Props & { t: TFunction }

const MyComponent = (props: PropsWithT) => /* something */

const translator: Translator<Props, PropsWithT> = translate('something')
const WrappedComp = translator(MyComponent)

// doesn't complain about missing props.t
<WrappedComp a="string" />

Notice how you have to pass in props for the HOC and for the original component?

Ideal Scenario

Ideally, you could use $Diff to do that work for you:

declare type Translator<P> = {
  (component: StatelessComponent<P>): Class<React$Component<void, $Diff<P, { t: TFunction }>, void>>;
  <Def, St>(component: Class<React$Component<Def, P, St>>): Class<React$Component<Def, $Diff<P, { t: TFunction }>, St>>;
}

Usage then becomes:

type Props = { a: string, t: TFunction }

const MyComponent = (props: Props) => /* something */

const translator: Translator<Props> = translate('something')
const WrappedComp = translator(MyComponent)

// doesn't complain about missing props.t
<WrappedComp a="string" />

Non-React HOF

An example of where $Diff could be used to type generic higher order functions:

type Obj = {
  a: string,
  b: string
}

const fn = (obj: Obj) => obj.a + obj.b

const hof = <Obj>(
  fn: (obj: Obj) => string
): (obj: $Diff<Obj, { b: string }>) => string => {
  return (obj) => fn({ ...obj, b: 'b' })
}

const fn2 = hof(fn)

// doesn't complain about missing obj.b
fn2({ a: 'a' })

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions