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