【问题标题】:Converting a JSON object into specific type将 JSON 对象转换为特定类型
【发布时间】:2021-07-21 01:03:39
【问题描述】:

我有一个 JSON 对象,其中包含一堆字符串...

{
    id: "1",
    amount: "57,000",
    title: "I am a test"
}

我怎样才能把它转换成这样的界面:

interface MyObj {
   id: number;
   amount: number;
   title: string;
}

我是否需要映射每个对象属性并尝试转换为必要的类型,或者我可以简单地尝试将 JSON 对象强制转换为类型?

为清楚起见,这里有一些附加信息。

我有一个上面示例对象的数组,JSON 所以...

[
{
    id: "1",
    amount: "57,000",
    title: "I am a test"
},
{
    id: "2",
    amount: "2347,000",
    title: "I am a test as well"
}
]

此 JSON 对象中的所有值都是字符串。每次我们在 TS 中使用对象时,我们都希望它们的类型是正确的。比如 id 和 amount 应该是数字,它们可以在存储到我们的 state 之前进行转换。

所以我想将上面数组中的JSON对象转换成特定的接口或类型。因为类型不匹配我不能只使用接口,我需要在实际与接口对齐之前进行一些转换或尝试转换为类型。这是一个问题,我如何映射数组中的 JSON 对象并将一些键从字符串转换为数字(可能?)。

【问题讨论】:

  • 由于amountid 实际上属于string 类型,因此转换无法按预期工作,还是您的示例中的错误?
  • 什么意思?您什么时候尝试处理这些 - 在编译时(生成 TS 源)之前、在编译时、在编译时之后/在运行时?
  • 类型故意不匹配。这部分是问题所在。我如何将具有所有字符串值的 JSON 对象转换为可观的接口。 IE。尝试将 id 和 number 强制转换为 number 或默认设置。
  • 57,000 中的逗号应该是小数分隔符还是千位分隔符

标签: javascript json typescript interface


【解决方案1】:

我认为您正在尝试做的是通过解析 JSON 对象将 JSON 对象转换为 JavaScript 对象。

您可以如何执行此操作的示例如下:

const json = '{"result": true, "count": 42}';
const obj = JSON.parse(json);

然后您可以像访问常规对象一样访问新的 JavaScript 对象 obj。它将包含与 json 对象中完全相同的信息。

有关此方法的更多信息,请访问:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse https://www.w3schools.com/js/js_json_parse.asp

【讨论】:

    【解决方案2】:

    JSON.parse reviver

    JSON.parse 可以采用可选的第二个参数,reviver 函数 -

    如果指定了reviver,则解析计算的值在返回之前进行转换。具体来说,计算值及其所有属性(从最嵌套的属性开始并继续到原始值本身)分别通过reviver 运行。然后它被调用,包含正在处理的属性的对象作为 this,属性名称作为字符串,属性值作为参数。如果reviver 函数返回undefined(或不返回任何值,例如,如果执行落在函数末尾),则从对象中删除该属性。否则,该属性被重新定义为返回值。

    function MyObject({ id, amount, title }) {
      this.id = id
      this.amount = amount
      this.title = title
    }
    
    function reviver(key, value) {
      if (value?.id && value?.amount && value?.title)
        return new MyObject(value)
      else
        return value
    }
    
    const json =
      `[{"id":"1","amount":"57,000","title":"I am a test"},{"id":"2","amount":"13,000","title":"I am also test"},{"id":"3","amount":"1,000","title":"I am a third test"},{"id":"4","amount":"200","something":"else"},1,"foo"]`
    
    const data =
      JSON.parse(json, reviver)
    
    for (const value of data)
      console.log(value)
    MyObject { id: '1', amount: '57,000', title: 'I am a test' }
    MyObject { id: '2', amount: '13,000', title: 'I am also test' }
    MyObject { id: '3', amount: '1,000', title: 'I am a third test' }
    { id: '4', amount: '200', something: 'else' }
    1
    foo
    

    做得更好

    revive 以上是一个有点脆弱的函数。因此,建议您的 JSON.stringify'd 数据包含 type 字段或类似字段 -

    [ { type: "MyObject", ... }, { type: "Another", ... }, "foo", 1, ... ]
    

    现在我们可以用一种简单的方式写reviver -

    function reviver(key, value) {
      switch (value?.type) {
        case "MyObject": return MyObject(value)
        case "OtherThing": return OtherThing(value)
        case "Another": return Another(value)
        default: return value                   // revive without modification
      }
    }
    

    【讨论】:

    • 我对问题的解读是 OP 拥有对象并希望从中生成 TS 接口。虽然,“强制转换”的提及表明他们可能想要生成这些对象(TS 中没有强制转换,只是类型断言 - 本质上是对编译器撒谎)。如果意图是产生它们,那么根据接口,idamount 是数字,而不是字符串。
    • 我想我误解了。对此感到抱歉。
    【解决方案3】:

    TypeScript 只是一个开发/构建时工具;这意味着强制转换(例如使用as)在运行时没有任何效果,例如将字符串转换为数字。强制转换或使用 as 只是告诉 TypeScript 明确地将值视为特定类型的一种方式。如果你试过这个:

    interface MyObj {
       id: number;
       amount: number;
       title: string;
    }
    
    const data = {
        id: "1",
        amount: "57,000",
        title: "I am a test"
    };
    
    const ofType = data as MyObj;
    

    ...TypeScript 将无法编译,因为data 与您的界面不兼容,因为类型不对齐。即使你强迫它:

    const ofType = data as unknown as MyObj;
    

    ...idamount 仍将是字符串,现在您已在应用程序中强加了一个错误。

    TypeScript 可作为确保代码健全性的质量保证工具;它没有为数据转换带来任何好处。因此,就像纯 JavaScript 一样,如果您需要将事物从一种类型转换为另一种类型,则必须编写自定义代码。例如,如果您发布了一个已解析的 JSON 数组:

    const converted: Array<MyObj> = data.map(item => ({
      id: parseInt(item.id),
      amount: parseInt(item.replace(/,/g, '')),
      title: item.title
    }));
    

    【讨论】:

    • 好的,所以如果我有一个包含这些 JSON 对象的数组,我需要尝试将数组中的每个对象解析为它的类型。
    • 是的,您可以使用类似在数组上调用map 并在该函数内部进行转换。
    • 这似乎最符合问题所在。为了清楚起见,我还添加了更多信息。
    【解决方案4】:

    一个简单的演员就可以了。

    看这里

    var test = {
      name: ""
    };
    
    // umnown type will be 
    
    console.log(test.name) // this is simple like test["name"].
    
    // Now if you want it to a specific type then
    
    interface Itest {
      name: string;
    }
    
    var myobj = test as Itest;
    // or 
    
    var myobj = < Itest > test;
    
    // then the property will be a known property
    
    console.log(myobj.name);
    

    【讨论】:

    • 1,TypeScript 中没有强制转换。 2. 它被称为“类型断言” 3. 它的工作原理是向编译器撒谎关于你有什么类型,它实际上并没有转换任何东西(再次 - 没有强制转换) .
    • 朋友阅读此acdcjunior.dev/…
    • 文章有误。没有强制转换 - 运行此示例 Playground Link - 代码编译但不进行转换。存在运行时错误,因为 id 实际上不是数字。
    • 是的,没有错误。如果您阅读我的示例,那么该属性将是一个已知属性,具有类型和名称。我从来没有说过转换。阅读我的示例,您会看到我写了已知和未知。请注意,您需要在 Visual Studio 上编写此示例,以便您理解
    • "我从没说过转换" -> 转换意味着转换。 TS 不进行强制转换,因为没有转换。并且建议一个类型断言类型不匹配只是一个很难在代码中找到错误的秘诀。您已经否决了编译器,因此您不会得到正常的编译时错误。只有运行时那些甚至可能不会立即显示。 极少类型断言是合适的。在所有这些中,您必须非常小心。这既不小心,也不适合使用类型断言。
    【解决方案5】:

    您所需要的是一个parseInt() 函数。

    如下使用:

    const obj = {
        id: "1",
        amount: "57,000",
        title: "I am a test"
    };
    
    print(parseInt(obj.amount))         <-    Number and not string
    

    如果要确认变量的类型,可以使用typeof操作符,如下:

    print(typeof parseInt(obj.amount))         
    

    【讨论】:

    • parseInt("57,000") 产生 57 而不是 57000
    【解决方案6】:

    已编辑

    我注意到给定的对象与interface MyObj不同

    因此你不能做type assertion(不能使用as)。您必须将给定对象转换为您的类型!

    那么你需要做什么 - 如果你知道给定的对象看起来像这样:

    const data: any = {
        id: "1",
        amount: "57,000",
        title: "I am a test"
    }
    

    你应该这样做:

    const myObj: MyObj = {
       id: parseInt(data['id']),
       amount: parseInt(data['amount'].replaceAll(',','')),
       title: data['title']
    }
    

    如果您不确定它看起来像 data,请考虑添加更多验证/默认值

    例如,如果 data['id'] 未定义,则 Id 将为 NaN 如果 data['title'] 未定义,也许你应该添加默认值

    【讨论】:

    • TypeScript 中没有强制转换。 as 只是推翻了编译器——它被称为类型断言。 您在此过程中没有得到任何转换!!! runnable example
    • 是的,你说得对!我使用了不正确的术语
    • 粗斜体部分更重要。使用 as 不会改变数据的任何内容。
    • 是的,你又说对了!我没有注意到界面与界面不同..我改变了帖子:)
    猜你喜欢
    • 2019-04-10
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 2021-10-30
    • 2012-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多