How to declare Flow types for a function which has fields?
Asked Answered
C

1

12

I am trying to write a Javascript project with strict flow typing everywhere. I also have a dependency on big-integer. There are no preset flow annotations in flow-typed unfortunately and Google is not supplying anything useful on the topic.

Like a lot of JavaScript packages, big-integer exports a single function, which is usually called bigInt. This can be called directly, like so: bigInt(13), bigInt("134e134"), etc., which creates objects which are big integers (I've decided to call the type of the return value of this function a "class" called "BigInteger" based on the documentation -- but I don't think the internals actually use classes since I believe the package came out before ES6).

This works fine for the output of the function and I can attach methods to that class and we're all good. However, bigInt itself has some methods, e.g. bigInt.lcm(123, 234). How can I document this?

declare module "big-integer-types" {
  declare class BigInteger {
    add(addend: BigIntInput): BigInteger;
    minus(subtractand: BigIntInput): BigInteger;
    /* snip */
  }
  declare type BigIntInput = number | string | BigInteger;
  declare type BigIntFn = (void | number | string | BigInteger) => BigInteger;
}

declare module "big-integer" {
  import type { BigIntFn } from "big-integer-types";
  declare export default BigIntFn
}

This works well for the fields of big integers, e.g. for type-checking bigInt(12).plus("144e53"). Which is great. But this doesn't include bigInt.lcm(134, 1551) and that gives a flow error.

The alternative is to declare the export of the big-integer module to be a type which has certain associated functions. For example:

declare module "big-integer-types" {
  declare type BigIntegerStaticMethods {
    lcm(a: BigIntInput, b: BigIntInput): BigInteger,
    /* snip */
  }

  declare type BigIntInput = number | string | BigInteger;
}

declare module "big-integer" {
  import type BigIntegerStaticMethods from "big-integer-types";
  declare export default BigIntegerStaticMethods
}

This works for the static methods, but I don't know how to say a "type" can be called. So I'm at a loss as to how to achieve both at once.

This seems weird because a function with fields is quite common in javascript and the flow documentation suggests they went through a lot of effort to have the type system support javascript as it is used. So I figure there is a flow syntax to achieve this, I just couldn't figure out what it was, and couldn't find it in the docs.

Comose answered 24/12, 2017 at 23:8 Comment(0)
I
4

You can declare an unnamed static function in the class:

declare type BigIntInput = number | string | BigInteger;
declare class BigInteger {
  add(addend: BigIntInput): BigInteger;
  minus(subtractand: BigIntInput): BigInteger;

  static lcm(a: BigIntInput, b: BigIntInput): BigInteger;
  static (data?: BigIntInput): BigInteger;  
} 

BigInteger.lcm(1,2);
BigInteger(4).add(5);
Irate answered 25/12, 2017 at 0:7 Comment(2)
I'm not sure why this answer is attracting so many upvotes. It does not work. The unnamed static function is not recognized by flow and causes a flow error.Comose
Can you elaborate about the error? This code doesn't fail for me at Flow/Try, also that's what we use at our codebase for such situations.Irate

© 2022 - 2024 — McMap. All rights reserved.