javascriptflowtype

Why is flow complaining that my variable is not a string?


My code is as follows (I believe this is mostly a typing issue so I don't think the actual code for downloading is relevant here):

...
TokenService.getToken(id).then(result => {
  const { read } = result;
  if (typeof read === 'string') {
    download(url_template, name, read, is_watermarked);
  }
});
**
 * Downloads a file
 * @param {string} urlTemplate The url to download
 * @param {string} name The name of the original file
 * @param {string} readToken The access token
 * @param {boolean} isWatermarked If a file has a watermark
 * @returns {void}
 */
const download = (urlTemplate: string, name: string, readToken: string, isWatermarked: boolean) => {
...

But flow keeps complaining with an errorr about deconstructing read:

Cannot call TokenService.getToken(...).then with function bound to onFulfill because property read is
missing in String [1] in the first argument.

The strange thing is, I've logged the variable type of read and it comes back as a string; so I'm not sure why flow is complaining...


Solution

  • Let's dive into your error messages:

    Cannot call TokenService.getToken(...).then with function bound to onFulfill because property read is
    missing in String [1] in the first argument.
    

    What this error says is that Flow thinks result is a String, and thus cannot read property result.read because Strings don't have such property ("property read is missing"). Instead of logging the variable type of read, log it's contents and see if it is a valid String.

    The second error

    Cannot call download with read bound to readToken because object type [1] is incompatible
    with string [2].
    

    Says that Flow thinks the type of read is other than String in this line:

    download(url_template, name, read, is_watermarked);
    

    This is why you should first check if read is for sure string, and then try setting it's type or overriding it (in Typescript it would be (read as string), but I don't know how Flow works sadly)

    Keep in mind that what you log into the console is a runtime value, and what Flow thinks a variable's type is, is different because it's only trying to guess what the type of variable will be, but it can't know for sure what will occur in the runtime.

    ===========================

    The answer below is incorrect, I left if here so people reading comments to this answer are not confused

    The problem is that when you hover over result object here,

    const { read } = result;
    

    you will see it's type is not set strongly. To bypass that, when you know your API responses are always correct and under result.read you will always find string, you can force strong type of the read variable like so:

      download(url_template, name, (read as string), is_watermarked);
    

    Keep in mind that logging a variable is different than working with Typescript. What you did was to check the runtime value, but Typescript only works on build level so it is unaware that your API will respond with good object.