Home > Blockchain >  Why doesn't typescript infer the final type inferred as string?
Why doesn't typescript infer the final type inferred as string?

Time:06-18

I have defined this type:

type StoreDataValue = string | Record<PropertyKey, any>;

And I have a parameter value that is of this type.

First I create a temp variable and assign it to value.

I then do a check to see if it's different than string use JSON.stringify to convert it to a string.

But typescript doesn't infer that the final result is string.

It shows this error when I try to use the final parsedValue:

Argument of type 'StoreDataValue' is not assignable to parameter of type 'string'. Type 'Record<PropertyKey, any>' is not assignable to type 'string'.ts(2345)

The code is the following:

type StoreDataValue = string | Record<PropertyKey, any>;

const storeData = async (key: string, value: StoreDataValue) => {
  try {
    let parsedValue = value;
    if (typeof parsedValue !== "string") {
      parsedValue = JSON.stringify(value);
    } else {
      parsedValue = value;
    }

    await AsyncStorage.setItem(key, parsedValue);

  } catch (e) {
    // ...
  }
};

If I just change the line typeof parsedValue ... to typeof value ... then the inference works.

Am I doing something wrong or not seeing the obvious?

CodePudding user response:

The problem is that this:

if (typeof parsedValue !== "string") {
  parsedValue = JSON.stringify(value);
}

narrows ONLY the type of parsedValue to string but does NOT automatically do any narrowing on the type of value. So, after this line the TypeScript type checker still thinks that value is of type string | Record<PropertyKey, any> and when you assign value to parsedValue in the else clause, the TypeScript checker thinks that you might revert the type of parsedValue back to string | Record<PropertyKey, any>.

If you remove the else clause of the if-statement, you would see that the error disappears. The reason for this is that there will no longer be a code path which assigns a value of type string | Record<PropertyKey, any> (i.e. the type of the value parameter) to parsedValue after parsedValue has been narrowed to string:

    let parsedValue = value;
    if (typeof parsedValue !== "string") {
      parsedValue = JSON.stringify(value);
    }

    await AsyncStorage.setItem(key, parsedValue); // This works just fine
  • Related