我有一个Typescript应用程序。我使用localstorage进行开发以存储我的对象,我在反序列化时遇到了问题。
我有一个类型为MeetingModel的对象会议:
export interface MeetingModel {
date: moment.Moment; // from the library momentjs
}
我使用JSON.stringify(meeting)
将此对象存储在localStorage中。
我认为stringify调用moment.toJson(),它返回一个iso字符串,因此存储的值为:{"date":"2016-12-26T15:03:54.586Z"}
。
当我检索这个对象时,我会这样做:
const stored = window.localStorage.getItem("meeting");
const meeting: MeetingModel = JSON.parse(stored);
问题是:meeting.date包含一个字符串而不是片刻!
所以,首先我想知道为什么TypeScript会发生这种情况?为什么我可以指定字符串值而不是Moment并且编译器同意?
其次,如何将我的对象从普通的JSON对象(又名字符串)恢复为Typescript类型?
我当然可以创建一个工厂,但是当我的对象数据库长大后,完成所有这些工作将会很痛苦。
也许首先有一个解决方案可以更好地存储在本地存储中?
谢谢
答案 0 :(得分:4)
1)TypeScript可选择输入。这意味着有类型系统严格的方法。 any
类型允许您进行动态输入。如果你知道自己在做什么,这可以派上用场,但当然你也可以用脚射击自己。
此代码将编译:
var x: string = <any> 1;
这里发生的事情是number
1被转换为any
,而TypeScript意味着它只是假设您作为开发人员知道它是什么以及如何使用它。由于any
类型随后被分配给string
TypeScript,即使您在运行时可能会出错,就像在编写JavaScript时出错一样。 / p>
当然这是设计上的。 TypeScript类型仅在编译期间存在。你在JSON.parse
放入什么类型的字符串对于TypeScript是不可知的,因为输入字符串仅在运行时存在,并且可以是任何事物。因此any
类型。 TypeScript确实提供了所谓的类型保护。类型保护是在编译时和运行时都能理解的一些代码,但这超出了你的问题的范围(如果你感兴趣,可以使用谷歌)。
2)序列化和反序列化数据通常不像调用JSON.stringify
和JSON.parse
那么简单。大多数类型信息都会丢失到JSON中,并且通常在运行时期间存储对象(在内存中)的方式与您希望存储它们以进行传输或存储(在内存,磁盘或任何其他介质中)的方式非常不同)。例如,在运行期间,您可能需要查找表,用户/会话状态,私有字段,库特定属性,而在存储中,您可能需要版本号,时间戳,元数据,不同类型的规范化等。您可以{{1你在JavaScript领域想要的任何东西,但这必然意味着它是一个好主意。您可能想要设计实际存储数据的方式。例如,iso字符串看起来很漂亮,但需要很多字节。如果您只有一些无关紧要,但是当您每秒传输数百万时,您可能需要考虑另一种格式。
我建议您为要保存的对象定义接口,并在模型对象上创建JSON.stringify
方法,这将返回您可以简单序列化的DTO(数据传输对象)与.toJson
。然后在返回途中,将JSON.stringify
any
输出转换为DTO,然后使用工厂函数或创建的构造函数将其转换回模型。这可能看起来像很多样板,但根据我的经验,它是完全值得的,因为现在您可以控制存储的内容,并且在不出现反序列化问题的情况下为您提供了很大的灵活性来更改模型。
答案 1 :(得分:2)
您可以使用JSON.parse
的reviver
功能将字符串转换回片刻:
JSON.parse(input, (key, value) => {
if (key == "date") {
return parseStringAsMoment(value);
} else {
return value;
});
检查浏览器对reviver的支持,因为它与基本JSON.parse不同