Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend Flow function type with additional properties

Flow v0.57

I'd like to define 2 function types, Foo and FancyFoo to help type check the following pattern:

const fooFn = () => ({ id: '...', type: '...' });

fooFn['HELLO'] = 'WORLD';
fooFn['test'] = () => {};

...

// now I can do this:
fooFn();
fooFn.HELLO;
fooFn.test();

The first function type is seemingly straightforward:

type Foo = () => {
  id :string,
  type :string
}

I'm stuck figuring out the second. It's not clear to me how to build off of function types.

I tried using intersection:

type FancyFoo = Foo & {
  HELLO :string,
  test :() => mixed
}

However, this approach fails:

// Errors:
2: type FancyFoo = Foo & {
                         ^ property `HELLO` of object type. Property not found in
7: const fooFn :FancyFoo = () => ({ id: '...', type: '...' });
                           ^ function

2: type FancyFoo = Foo & {
                         ^ property `test` of object type. Property not found in
7: const fooFn :FancyFoo = () => ({ id: '...', type: '...' });
                           ^ function

How do I define a FancyFoo function type that "extends" Foo but also includes the extra properties?

Link to Flow Try


UPDATE

Here's a more specific example for what I'm trying to do:

type Foo = () => { id :string, type :string }

export function getFancyFoo(type :string) :FancyFoo {

  const id :string = randomId();
  const foo :Foo = getFoo(id, type);

  ['A', 'B', 'C'].forEach((thing :string) => {
    foo[thing.toUpperCase()] = thing.toUpperCase();
    foo[thing.toLowerCase()] = () => { /* function that does fancy thing */ };
  });

  return foo;
}

The getFancyFoo function will first get a Foo function, and then decorate/enhance it with extra properties. At the end of the function, foo will look like this (Chrome Dev Tools):

FancyFoo example

FancyFoo is a Foo function, but it also has the extra properties added to it. I'm stuck on defining the FancyFoo function type.

like image 593
Hristo Avatar asked Oct 29 '22 23:10

Hristo


1 Answers

Use Callable Object syntax, e.g.

type OutputInterceptorType = {|
  <T>(routine: () => Promise<T> | T): Promise<T>,
  output: ''
|};
like image 186
Gajus Avatar answered Nov 15 '22 07:11

Gajus