flowtype

Is it possible to use a type which would represent many class types?


I'm facing a problem with Facebook Flow, briefly stated in the title of the question. The reason is that I don't want to specify Class<Bird> | Class<Snake> 100 times.

Here is a simplified example:

There are many classes which all implement a particular interface Animal. I need to be able to specify, that, let's say, a function accepts values of type T and those values are classes which implement Animal. That is if I call return new c(); in the function (as in the code snippet below), its return type will be T, an instance of a class which implements Animal;

Currently, I'm getting this error. But I've tried numerous other approaches: type assertions, object types with intersection operators etc. Those didn't work either.

//@flow strict

interface Animal {
  eat(): void,
}

class Dog implements Animal {
  constructor() { }
  eat() { }
  bark() { }
}

foo(Dog);

function foo(c: Class<Animal>) {
  return new c();     ■ Cannot call `c` because property `constructor` is missing in  `Animal` [1].
}

Is this possible to do? Even if it will be to skip somehow type checks in this particular place.


Solution

  • My current solution is to ignore that error.

    And my conclusion is that it's not only justified in this situation, but it's the correct way. Because the Flow documentation explicitly mentions, that Flow is not expected to handle every possible syntax construct (sounds pretty reasonable, since it's main benefit seems to be to statically define certain "contracts" between parts of an application, not to be a sort of "static runtime" engine for types).

    Flow reports many different kinds of errors for many common programming mistakes, but not every JavaScript pattern can be understood by Flow.

    So in my case I just added the comment and declared the return type:

    function foo(c: Class<Animal>): Animal {
      //$FlowExpectedError[prop-missing]
      return new c();
    }