如何在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
相关产品推荐
相关产品推荐

