Flow does not support certain JavaScript (ECMAScript) built-in methods, what do I do?

657 Views Asked by At

As an embedded software engineer used to strictly-typed languages, I was compelled to use Flow (https://flow.org) when writing an experimental utility in JavaScript.

About 10 minutes into writing code with JS+Flow, Flow ('flow-bin' binary) gave me the following error:

Cannot call string.trim().replaceAll because property replaceAll (did you mean replace?) is missing in String [1].

with regards to the following (Flow-annotated) code:

static sanitizeString(string : string) : string {
    return string.trim().replaceAll(/(?:\s+|\.+)/g, "");
}

Flow tells me that it can not find the (fairly-widely implemented) string.prototype.replaceAll(...) function in (what seems to be a) "symbolic" definitions file: tmp/flow/flowlib_1fa18dde633e97c7_501/core.js

Which begs the question:

Are Flow users solely at the mercy of the provisioned definitions file when it comes to using (widely-implemented) methods defined by ECMAScript standards (or proposals/drafts for that matter, given the fast-paced nature of browsers' implementation of ECMAScript)?

Do I have to modify the definitions file (core.js) to resolve this problems?

2

There are 2 best solutions below

1
On BEST ANSWER

First of all, I don't have direct answer to this question, but I'll try to elaborate the problem a bit.

But this is rather interesting. It truly throws that error: Flow Example

Now, it gets even more interesting since TypeScript throws the same error: TS Example

However, TS is more robust with the error message:

Property 'replaceAll' does not exist on type 'string'. Do you need to change your target library? Try changing the lib compiler option to 'esnext' or later.

Hence, I suggest you to follow that advice and switch flow compiler to follow different set of rules (in .flowconfig I guess?).

0
On

I think we need to strive to contextualize this question a bit before it can really be considered answered.

Flow provides a base set of types as a good starting point for most use cases. These are regularly updated, but not really as part of a methodical process. Users often open PRs against flow to update the provided libdefs with pieces they are interested in using, and that's probably the most common way these updates occur right now. Changes to the core types are usually very simple and make good "first PRs". It's also worthwhile to note that flow has far fewer incoming PRs than typescript.

So the reality on the ground ends up being that flow's provided types are not always up to date with every piece of the most recent spec. The question becomes, how is one expected to manage this situation?

One option is to stop using the provided types. Flow has a config option:

no_flowlib (boolean)

Flow has builtin library definitions. Setting this to true will tell Flow to ignore the builtin library definitions.

The default value is false.

By setting this to true we'll no longer get any of flow's provided types. This allows us to use only the types we specify. A common practice is to toggle this to true, copy flow's provided types into the project's local libdefs, and make modifications to them in-place. This would allow us to get all the benefits of using the provided types while also being able to make any necessary modifications. The main downside is that the types must now be updated manually whenever upgrading the flow version.

The other option, of course, is to just open a PR. Flow releases fairly rapidly and reliably, and changes to the provided libdefs are usually merged quickly.

I'll withhold comment on how satisfactory this state of affairs may or may not be, but if anybody is facing these concerns then hopefully this is all the information you need in order to formulate solutions.