如何在ts中正确键入“ JSON.parse()”?

时间:2019-07-02 16:26:56

标签: typescript

JSON.parse(aString)默认情况下键入为any。但是,any还包括函数,日期,正则表达式和其他无法解析的类。

现在,我怀疑如果我们利用ts 2.8中引入的条件类型和3.0的推断,我们会更加准确,但是我对如何做到这一点有些困惑。也许我缺少一些现有的基本类型,有人可以建议我吗?

const good: BasicType = JSON.parse(aString); // what I need
const bad: any = JSON.parse(aString); // what I do have now

1 个答案:

答案 0 :(得分:1)

据我所知,TypeScript标准库中没有对应于可以从JSON序列化/反序列化的类型的内置类型名称。 GitHub中有一个issue建议添加一个,尽管看起来并没有太多动静。

幸运的是,您很容易为此创建自己的类型,例如在上述GitHub问题的注释中建议的this one

type AnyJson =  boolean | number | string | null | JsonArray | JsonMap;
interface JsonMap {  [key: string]: AnyJson; }
interface JsonArray extends Array<AnyJson> {}

然后您可以使用declaration merging重载parse()方法以返回AnyJson而不是any

interface JSON {
  parse(
    text: string,
    reviver?: ((this: any, key: string, value: any) => any) | undefined
  ): AnyJson;
}

(请注意,如果您的代码在模块中,则需要使用global augmentation才能使以上代码正常工作

让我们看看它是否有效:

const x = JSON.parse('{"id": 123}'); // x is AnyJson

由于已知xAnyJson而不是any,因此您现在可以对其进行类型保护,并且编译器应该更了解其可能的结构:

if (x !== null && typeof x === "object" && !Array.isArray(x)) {
  // x narrowed to JsonMap
  Object.keys(x).forEach(k => {
    const y = x[k];
    // y is also AnyJson
    console.log("key=" + k + ", value=" + String(y));
  });
  // key=id, value=123
}

一切正常。话虽如此,实际上,类型AnyJson并不比any更具体。我想您会获得从可能的值/元素/属性中排除函数/方法的好处,这并不是没有……它可能不足以保证修改TypeScript标准库。如this comment中所述,AnyJson类型为“在any的分散距离内”。

好的,希望能有所帮助;祝你好运!

Link to code