You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将TypeScript多值数组映射为Go结构体?

最优方案:自定义JSON反序列化逻辑

直接用[][]interface{}后做类型断言不仅繁琐,还容易因类型不匹配触发运行时 panic,最优方案是给对应结构体实现json.Unmarshaler接口,把数组格式的JSON直接反序列化为强类型结构体,彻底摆脱类型断言的麻烦。

步骤1:定义强类型结构体

根据你的TypeScript类型定义,对应Go结构体如下(注意处理null和可选字段):

type Extra struct {
    Reason string
    Value  int64
}

type Item struct {
    ID1     int64
    ID2     int64
    ID3     *int64  // 对应TypeScript的number,允许null,用指针接收
    Address string
    Type    string
    Active  bool
    Extra   *Extra  // 可选数组字段,用指针标记可选性
}

type Response struct {
    Data []Item `json:"data"`
}

步骤2:给Item实现UnmarshalJSON方法

在这个方法里手动解析数组的每个元素,完成类型转换和赋值,同时处理异常情况:

import "encoding/json"
import "fmt"

func (i *Item) UnmarshalJSON(data []byte) error {
    // 先把JSON数组反序列化为interface{}切片
    var arr []interface{}
    if err := json.Unmarshal(data, &arr); err != nil {
        return err
    }

    // 校验必填字段的数组长度
    if len(arr) < 6 {
        return fmt.Errorf("invalid item array: expected at least 6 elements, got %d", len(arr))
    }

    // 解析第1个字段:number -> int64
    id1, ok := arr[0].(float64)
    if !ok {
        return fmt.Errorf("id1 must be a number")
    }
    i.ID1 = int64(id1)

    // 解析第2个字段:number -> int64
    id2, ok := arr[1].(float64)
    if !ok {
        return fmt.Errorf("id2 must be a number")
    }
    i.ID2 = int64(id2)

    // 解析第3个字段:允许为null
    if arr[2] != nil {
        id3, ok := arr[2].(float64)
        if !ok {
            return fmt.Errorf("id3 must be a number or null")
        }
        val := int64(id3)
        i.ID3 = &val
    } else {
        i.ID3 = nil
    }

    // 解析第4个字段:string
    addr, ok := arr[3].(string)
    if !ok {
        return fmt.Errorf("address must be a string")
    }
    i.Address = addr

    // 解析第5个字段:string
    typ, ok := arr[4].(string)
    if !ok {
        return fmt.Errorf("type must be a string")
    }
    i.Type = typ

    // 解析第6个字段:boolean
    active, ok := arr[5].(bool)
    if !ok {
        return fmt.Errorf("active must be a boolean")
    }
    i.Active = active

    // 解析第7个可选字段:[string, number]
    if len(arr) >=7 && arr[6] != nil {
        extraArr, ok := arr[6].([]interface{})
        if !ok || len(extraArr) !=2 {
            return fmt.Errorf("extra must be a [string, number] array or null")
        }
        reason, ok := extraArr[0].(string)
        if !ok {
            return fmt.Errorf("extra reason must be a string")
        }
        val, ok := extraArr[1].(float64)
        if !ok {
            return fmt.Errorf("extra value must be a number")
        }
        i.Extra = &Extra{
            Reason: reason,
            Value:  int64(val),
        }
    }

    return nil
}

步骤3:使用方式

现在你可以直接把JSON反序列化到Response结构体,全程不需要类型断言:

// 假设jsonBytes是你的JSON数据字节流
var resp Response
err := json.Unmarshal(jsonBytes, &resp)
if err != nil {
    // 处理反序列化错误
}

// 直接访问强类型字段
for _, item := range resp.Data {
    fmt.Println(item.ID1)
    if item.ID3 != nil {
        fmt.Println(*item.ID3) // 非null时再取值
    }
    if item.Extra != nil {
        fmt.Println(item.Extra.Reason, item.Extra.Value)
    }
}

为什么这是最优方案?

  • 强类型安全:编译时就能检查字段类型,避免运行时类型断言出错
  • 可读性高:直接访问结构体字段,代码逻辑更清晰
  • 性能更好:避免了多次类型断言的开销,反序列化逻辑一次性完成
  • 可维护性强:如果TypeScript类型有变更,只需要修改结构体和Unmarshal方法即可

内容的提问来源于stack exchange,提问作者Camopy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:45:35