TypeScript中惯用的方式来解析JSON?

时间:2019-07-07 17:05:42

标签: json typescript

我有一个接口IMsg,并且想解析JSON,所以我有一个实现我的IMsg接口的对象。

此代码

interface IMsg {
  text: string;
  channels: Set<string>;
}
const msg: IMsg = JSON.parse(`{
  "text": "test",
  "channels": ["latest", "something"]
}`);
console.log(msg.channels.has('latest'));

将在运行时产生此错误:

TypeError: msg.channels.has is not a function

因为msg.channels不是Set<string>

  1. 为什么编译器不会抱怨我尝试将any的对象分配给msg类型的IMsg
  2. 在没有太多样板代码的情况下将JSON正确解析为msg的最惯用,简洁的方法是什么?

2 个答案:

答案 0 :(得分:1)

  

为什么编译器不会抱怨我试图将任何对象分配给IMsg类型的味精?

因为the type any的确切含义是:请勿对此变量进行任何类型验证。就像JavaScript中一样,它可以是任何东西。

  

在没有太多样板代码的情况下将JSON正确解析为msg的最惯用,简洁的方法是什么?

我会用类似的东西

interface JsonMessage {
  text: string;
  channels: Array<string>;
}

const jsonMessage: JsonMessage = JSON.parse(`{
  "text": "test",
  "channels": ["latest", "something"]
}`);

const message: IMsg = {
  text: jsonMessage.text,
  channels: new Set(jsonMessage.channels)
};

答案 1 :(得分:0)

类似于JB Nizet的响应,我为JSON消息创建了一个单独的接口。但是,我不想重复每个字段。

以下代码将IMsg作为基本接口。它将删除channels: Set<string>字段,并将其添加回类型为string[]的字段。为了在两者之间进行转换,我编写了一个转换器函数parseMsg

interface IMsg {
  text: string;
  channels: Set<string>;
}

// create new interface for JSON handling based on IMsg
// and replace "channels: Set<string>" with "channels: string[]" 
type IMsgJSON = Omit<IMsg, 'channels'> & {
  channels: string[],
};

// convert from IMsgJSON to IMsg
function parseMsg(msgJSON: IMsgJSON): IMsg {
  const { channels, ...otherFields } = msgJSON;
  return {
    channels: new Set<string>(channels),
    ...otherFields,
  };
}

let msg = parseMsg(JSON.parse(`{
  "text": "test",
  "channels": ["latest", "something"]
}`));
console.log(msg.channel.has('latest'));