为什么打字稿不推断出推断为字符串的最终类型?



我已经定义了这个类型:

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

我有一个这种类型的参数value

首先,我创建了一个临时变量并将其分配给value

然后我做一个检查,看看它是否不同于string使用JSON.stringify将其转换为string

但是typescript并没有推断出最终的结果是string

当我尝试使用最后的parsedValue:

时显示这个错误

类型为'StoreDataValue'的实参不能赋值给'string'类型的形参。类型'Record<PropertyKey,>'不能赋值给类型'string'.ts(2345)

代码如下:

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) {
// ...
}
};

如果我只是将typeof parsedValue ...行更改为typeof value ...,那么推理工作。

是我做错了什么还是没有看到明显的?

问题是:

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

只将parsedValue的类型缩小为string,但不会自动缩小value的类型。所以,在这行之后,TypeScript类型检查器仍然认为valuestring | Record<PropertyKey, any>类型,当你在else子句中将value赋值给parsedValue时,TypeScript检查器认为你可能会将parsedValue的类型还原为string | Record<PropertyKey, any>

如果您删除If语句的else子句,您将看到错误消失。这样做的原因是,在parsedValue被缩小到string之后,将不再有一个将string | Record<PropertyKey, any>类型的值(即value参数的类型)分配给parsedValue的代码路径:

let parsedValue = value;
if (typeof parsedValue !== "string") {
parsedValue = JSON.stringify(value);
}
await AsyncStorage.setItem(key, parsedValue); // This works just fine