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

如何在Dart中实现类似TypeScript的联合类型并适配json_serializable

Dart中实现联合类型并适配json_serializable的方案

Dart没有原生联合类型支持,要实现你需要的boolean | {quality: string; link: string}[]类型,可以通过**密封类(sealed class)**配合json_serializable的自定义转换器来实现,以下是完整实现方案:


1. 依赖配置

先确保pubspec.yaml中包含必要依赖:

dependencies:
  flutter:
    sdk: flutter
  json_annotation: ^4.8.1

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.4.4
  json_serializable: ^6.7.0

2. 核心代码实现

创建user.dart文件,写入以下代码:

import 'dart:convert';
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

// 对应TS中的单个图片对象
@JsonSerializable()
class ImageItem {
  final String quality;
  final String link;

  ImageItem({required this.quality, required this.link});

  factory ImageItem.fromJson(Map<String, dynamic> json) => _$ImageItemFromJson(json);
  Map<String, dynamic> toJson() => _$ImageItemToJson(this);
}

// 密封类实现联合类型:要么是禁用状态,要么是图片列表
sealed class ImageUnion {}

class ImageDisabled extends ImageUnion {}

class ImageList extends ImageUnion {
  final List<ImageItem> images;
  ImageList(this.images);
}

// 自定义转换器,处理ImageUnion与JSON的互转
class ImageUnionConverter implements JsonConverter<ImageUnion, dynamic> {
  const ImageUnionConverter();

  @override
  ImageUnion fromJson(dynamic json) {
    if (json is bool && json == false) {
      return ImageDisabled();
    } else if (json is List) {
      return ImageList(json.map((e) => ImageItem.fromJson(e)).toList());
    }
    throw FormatException('不符合ImageUnion类型的JSON数据:${json.runtimeType}');
  }

  @override
  dynamic toJson(ImageUnion object) {
    if (object is ImageDisabled) {
      return false;
    } else if (object is ImageList) {
      return object.images.map((e) => e.toJson()).toList();
    }
    throw ArgumentError('未知的ImageUnion子类:${object.runtimeType}');
  }
}

// User数据类
@JsonSerializable()
class User {
  final String id;
  final String name;

  @ImageUnionConverter()
  final ImageUnion image;

  User({required this.id, required this.name, required this.image});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

3. 生成序列化代码

在终端执行以下命令,生成自动序列化/反序列化的.g.dart文件:

flutter pub run build_runner build

4. 使用示例

// 对应TS中的user1(禁用图片)
final user1 = User(
  id: "1",
  name: "John Doe",
  image: ImageDisabled(),
);
print(user1.toJson()); // 输出:{"id":"1","name":"John Doe","image":false}

// 对应TS中的user2(多质量图片列表)
final user2 = User(
  id: "1",
  name: "John Doe",
  image: ImageList([
    ImageItem(quality: "small", link: "https://example.com/image1"),
    ImageItem(quality: "medium", link: "https://example.com/image2"),
    ImageItem(quality: "large", link: "https://example.com/image3"),
  ]),
);
print(user2.toJson()); // 输出包含图片数组的JSON结构

// 从JSON反序列化
final jsonUser1 = '{"id":"1","name":"John Doe","image":false}';
final parsedUser1 = User.fromJson(jsonDecode(jsonUser1));
assert(parsedUser1.image is ImageDisabled);

final jsonUser2 = '''
{"id":"1","name":"John Doe","image":[
  {"quality":"small","link":"https://example.com/image1"},
  {"quality":"medium","link":"https://example.com/image2"},
  {"quality":"large","link":"https://example.com/image3"}
]}
''';
final parsedUser2 = User.fromJson(jsonDecode(jsonUser2));
assert(parsedUser2.image is ImageList);

关键说明

  • 密封类ImageUnion限制了仅能有ImageDisabled和ImageList两个子类,保证类型安全,避免非法值
  • 自定义转换器ImageUnionConverter负责处理两种类型与JSON的映射逻辑,反序列化时会严格校验输入类型
  • 完全适配json_serializable的生成流程,无需手动编写大量序列化代码

内容的提问来源于stack exchange,提问作者rajput-hemant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:13:14