{"id":21175360,"url":"https://github.com/6thsolution/dart_sealed","last_synced_at":"2025-07-09T21:31:52.103Z","repository":{"id":45559468,"uuid":"352049105","full_name":"6thsolution/dart_sealed","owner":"6thsolution","description":"Dart and Flutter sealed class generator and annotations, with match methods and other utilities. There is also super_enum compatible API.","archived":false,"fork":false,"pushed_at":"2024-03-26T10:26:16.000Z","size":935,"stargazers_count":17,"open_issues_count":6,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-04T23:02:07.557Z","etag":null,"topics":["annotation","annotations","dart","equality","example","flutter","generator","generic","legacy","null-safe","null-safety","sealed","sealed-class"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/sealed_annotations","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/6thsolution.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-03-27T10:56:46.000Z","updated_at":"2024-05-22T01:50:20.000Z","dependencies_parsed_at":"2025-05-28T20:39:18.776Z","dependency_job_id":"2e0d2717-4f14-4baa-89dd-b7ee26f6fecb","html_url":"https://github.com/6thsolution/dart_sealed","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/6thsolution/dart_sealed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thsolution%2Fdart_sealed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thsolution%2Fdart_sealed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thsolution%2Fdart_sealed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thsolution%2Fdart_sealed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/6thsolution","download_url":"https://codeload.github.com/6thsolution/dart_sealed/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/6thsolution%2Fdart_sealed/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264503949,"owners_count":23618762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotation","annotations","dart","equality","example","flutter","generator","generic","legacy","null-safe","null-safety","sealed","sealed-class"],"created_at":"2024-11-20T16:59:09.972Z","updated_at":"2025-07-09T21:31:51.775Z","avatar_url":"https://github.com/6thsolution.png","language":"Dart","readme":"# Dart Sealed Class Generator\n\n[![build](https://img.shields.io/github/workflow/status/6thsolution/dart_sealed/Dart?label=build)](https://github.com/6thsolution/dart_sealed/actions/workflows/dart.yml)\n[![build](https://img.shields.io/codecov/c/gh/6thsolution/dart_sealed?label=coverage)](https://codecov.io/gh/6thsolution/dart_sealed)\n[![pub](https://img.shields.io/pub/v/sealed_annotations.svg?color=blue\u0026label=sealed_annotations)](https://pub.dev/packages/sealed_annotations)\n[![pub](https://img.shields.io/pub/v/sealed_generators.svg?color=blue\u0026label=sealed_generators)](https://pub.dev/packages/sealed_generators)\n[![pub](https://img.shields.io/pub/v/sealed_writer.svg?color=blue\u0026label=sealed_writer)](https://pub.dev/packages/sealed_writer)\n\nGenerate sealed class hierarchy for Dart and Flutter.\n\n## Features\n\n* Generate sealed class with abstract super type and data sub-classes.\n* Static factory methods. for example `Result.success(data: 0)`.\n* Cast methods. for example `a.asSuccess`, `a.isSuccess` or `a.asSuccessOrNull`.\n* Three types of equality and hashCode generation : data (like kotlin data classes), identity and distinct.\n* Implement data equality with popular equatable library.\n* Support for generics. even types can be mixed.\n* Support for nullable and non-nullable types in null-safe projects.\n* Support for using one sealed type in another.\n* Support for null-safety.\n* Generate toString for data classes.\n* Generate 6 types of different matching methods. like `when`, `maybeWhen` and `map`.\n\n## Usage\n\nAdd dependencies in your `pubspec.yaml` file.\n\n```yaml\ndependencies:\n  sealed_annotations: ^latest.version\n\ndev_dependencies:\n  sealed_generators: ^latest.version\n```\n\nImport `sealed_annotations`.\n\n```dart\nimport 'package:sealed_annotations/sealed_annotations.dart';\n```\n\nAdd `part` pointing to a file which you want classes be generated in. with `.sealed.dart` extension.\n\n```dart\npart 'weather.sealed.dart';\n```\n\nAdd `@Sealed` annotation, and an abstract private class as a manifest for generated code. For example:\n\n```dart\n@Sealed()\nabstract class _Weather {\n  void sunny();\n\n  void rainy(int rain);\n\n  void windy(double velocity, double? angle);\n}\n```\n\nThen run the following command to generate code for you. If you are developer for flutter:\n\n```bash\nflutter pub run build_runner build\n```\n\nAnd if you are developing for pure dart:\n\n```bash\ndart run build_runner build\n```\n\nThe generated code will look like: (the following code is summarised)\n\n```dart\nabstract class Weather {\n  const factory Weather.rainy({required int rain}) = WeatherRainy;\n\n  bool get isRainy =\u003e this is WeatherRainy;\n\n  WeatherRainy get asRainy =\u003e this as WeatherRainy;\n\n  WeatherRainy? get asRainyOrNull {\n    /* ... */\n  }\n\n  /* ... */\n\n  R when\u003cR extends Object?\u003e({\n    required R Function() sunny,\n    required R Function(int rain) rainy,\n    required R Function(double velocity, double? angle) windy,\n  }) {\n    /* ... */\n  }\n\n  R maybeWhen\u003cR extends Object?\u003e({\n    R Function()? sunny,\n    R Function(int rain)? rainy,\n    R Function(double velocity, double? angle)? windy,\n    required R Function(Weather weather) orElse,\n  }) {\n    /* ... */\n  }\n\n  R? whenOrNull\u003cR extends Object?\u003e({\n    R Function()? sunny,\n    R Function(int rain)? rainy,\n    R Function(double velocity, double? angle)? windy,\n    R Function(Weather weather)? orElse,\n  }) {\n    /* ... */\n  }\n\n  R map\u003cR extends Object?\u003e({\n    required R Function(WeatherSunny sunny) sunny,\n    required R Function(WeatherRainy rainy) rainy,\n    required R Function(WeatherWindy windy) windy,\n  }) {\n    /* ... */\n  }\n\n  R maybeMap\u003cR extends Object?\u003e({\n    R Function(WeatherSunny sunny)? sunny,\n    R Function(WeatherRainy rainy)? rainy,\n    R Function(WeatherWindy windy)? windy,\n    required R Function(Weather weather) orElse,\n  }) {\n    /* ... */\n  }\n\n  R? mapOrNull\u003cR extends Object?\u003e({\n    R Function(WeatherSunny sunny)? sunny,\n    R Function(WeatherRainy rainy)? rainy,\n    R Function(WeatherWindy windy)? windy,\n    R Function(Weather weather)? orElse,\n  }) {\n    /* ... */\n  }\n}\n\nclass WeatherSunny extends Weather {\n  /* ... */\n}\n\nclass WeatherRainy extends Weather with EquatableMixin {\n  WeatherRainy({required this.rain});\n\n  final int rain;\n\n  @override\n  String toString() =\u003e 'Weather.rainy(rain: $rain)';\n\n  @override\n  List\u003cObject?\u003e get props =\u003e [rain];\n}\n\nclass WeatherWindy extends Weather {\n  /* ... */\n}\n```\n\nNotes:\n\n- Prefer using factories in super class instead of sub-class constructors. like `Whether.rainy()` instead\n  of `WhetherRainy()`\n- Minimize usage of cast methods, most of the time they can be replaced with a match method.\n\n## Equality and generated class names\n\nYou can choose between three types of equality using `@WithEquality(...)` annotation. Default equality is `data` if not\nspecified. This will become default equality for all sub-classes. You can change equality of each sub-class by using\nthis annotation on individual methods.\n\nEquality types:\n\n* `data` Equality is implemented with Equatable package. It behaves like kotlin data classes.\n* `identity` Only identical instances are equal. It's like when you don't implement any specific equality.\n* `distinct` All the instances are not equal with each other. Even an instance is not equal with itself.\n\nA basic example:\n\n```dart\n@Sealed()\nabstract class _Weather {\n  void sunny();\n\n  void rainy(int rain);\n\n  void windy(double velocity, double? angle);\n}\n```\n\nIn the proceeding example all classes will have `data` equality. For example if you wanted `identity` equality for all\nclasses but using `distinct` equality for `windy`:\n\n```dart\n@Sealed()\n@WithEquality(Equality.identity)\nabstract class _Weather {\n  void sunny();\n\n  void rainy(int rain);\n\n  @WithEquality(Equality.distinct)\n  void windy(double velocity, double? angle);\n}\n```\n\nAn abstract super class is generated with name equal to name of manifest class without the underline (here `Weather`).\nEach method will become a sub-class. There should be at least one method. sub-class names are based on method name\nprefixed with super class name (for example `WeatherSunny`). Naming process can be tailored with use of `@WithPrefix`\nand `@WithName` annotations. Each method argument will become a field in corresponding sub-class. Field names are equal\nto argument names and field types are equal to argument types or dynamic if not specified. Argument types can be\noverridden using `@WithType` annotation for example when type information is not available at build time. Note that you\ncan have nullable and non-nullable fields.\n\nTo change prefix of sub-class names which by default is top class name, you can use `@WithPrefix` annotation. for\nexample:\n\n```dart\n@Sealed()\n@WithPrefix('Hello')\nabstract class _Weather {\n  void sunny();\n}\n```\n\nNow `sunny` will be named `HelloSunny` instead of the default `WeatherSunny`. You can use `@WithPrefix('')` to remove\nall prefix from sub-class names.\n\nTo change sub-class names directly you can use `@WithName` annotation. It will override `WithPrefix` if specified. for\nexample:\n\n```dart\n@Sealed()\nabstract class _Weather {\n  @WithName('Hello')\n  void sunny();\n}\n```\n\nNow `sunny` will be named `Hello` instead of the default `WeatherSunny`. This is useful if you want not to use prefix\nfor some items.\n\nAlmost all methods on sealed classes use short names extracted from manifest method names. Full sub-class names are not\nused. It is recommended not to use sub-classes directly. There are factory methods for each item on super class.\n\n## Generic Usage\n\nFor generic sealed classes you should write manifest class like a generic class which you are implementing.\n\nIt is recommended that if you want nullable generic fields, declare a generic parameter as `T extends Base?` and use `T`\nwithout nullability suffix. If you want non-nullable generic fields declare a generic parameter as `T extends Base` and\nuse `T` without nullability suffix. If you don't specify upper bound it will default to `Object?` so your generic types\nwill be nullable.\n\n```dart\nimport 'package:sealed_annotations/sealed_annotations.dart';\n\npart 'result.sealed.dart';\n\n@Sealed()\nabstract class _Result\u003cD extends num\u003e {\n  void success(D data);\n\n  void error(Object exception);\n}\n```\n\nOr you can have multiple generic types and even mix them.\n\n```dart\nimport 'package:sealed_annotations/sealed_annotations.dart';\n\npart 'result.sealed.dart';\n\n@Sealed()\nabstract class _Result\u003cD extends num, E extends Object\u003e {\n  void success(D data);\n\n  void error(E exception);\n\n  void mixed(D data, E exception);\n}\n```\n\n## Dynamic types and Using one sealed type in another\n\nConsider you have a sealed result type like:\n\n```dart\n@Sealed()\nabstract class _Result\u003cD extends Object\u003e {\n  /* ... */\n}\n```\n\nYou want to use this type in another sealed type.\n\n```dart\n@Sealed()\nabstract class _WeatherInfo {\n  void fromInternet(Result\u003cWeatherData\u003e result);\n}\n```\n\nIf you generate for `WeatherInfo` you will see that result has `dynamic` type. It is because `Result` itself is not code\ngenerated at build time.\n\nYou should use `@WithType` annotation.\n\n```dart\n@Sealed()\nabstract class _WeatherInfo {\n  void fromInternet(@WithType('Result\u003cWeatherData\u003e') result);\n\n  // you can also have nullable types.\n  void nullable(@WithType('Result\u003cWeatherData\u003e?') result);\n}\n```\n\n### Hierarchy Feature\n\nIf Sealed classes are in the same file you can reference them directly using their manifest class name. This is to\navoid `@WithType` annotation and better refactoring capability.\n\n```dart\n@Sealed()\nabstract class _Apple {\n  void eat();\n}\n\n@Sealed()\nabstract class _Banana {\n  void eat();\n}\n\n@Sealed()\nabstract class _Basket {\n  void friends(_Apple? apple, _Banana? banana);\n\n// or equivalently\n// void friends(@WithType('Apple?') apple, @WithType('Banana?') banana);\n}\n```\n\nAnd for generic case:\n\n```dart\n@Sealed()\nabstract class _Result\u003cD extends num\u003e {\n  void success(D data);\n\n  void error(Object exception);\n}\n\n@Sealed()\nabstract class _Basket {\n  void hold(_Result\u003cint\u003e x);\n\n// or equivalently:\n// void hold(@WithType('Result\u003cint\u003e') x);\n}\n```\n\n`@WithType` annotation will override hierarchy feature if present.\n\n## Common Fields\n\nSometimes you need some fields to be present in all of your sealed classes. For example consider making a sealed class\nfor different types of errors, and all of them are required to have `code` and `message`. It is very annoying to add\ncode and message to all of sealeds manually. Also if you have an error object you are unable to get its code or message\nwithout using cast or match methods. Here you can use common fields.\n\nTo declare a common field you can add a getter or a final field to a manifest class, and it will automatically be added\nto all of your sealed classes. for example:\n\n```dart\n@Sealed()\nabstract class _ApiError {\n  // using getter\n  String get message;\n\n  // using final field\n  final String? code = null;\n\n  // code and message will be added to this automatically\n  void internetError();\n\n  void badRequest();\n\n  void internalError(Object? error);\n}\n```\n\nYou can also use a constructor in pair with final fields equivalently.\n\ncommon fields are available on `ApiError` objects as well as it's sub-classes.\n\nIf you specify common fields in your seaeld classes it has no effect. for example:\n\n```dart\n@Sealed()\nabstract class _Common {\n  Object get x;\n\n  // one and two will have identical signatures\n  void one(Object x);\n\n  void two();\n}\n```\n\nYou can use sub-class of common field type in sealed classes. For example:\n\n```dart\n@Sealed()\nabstract class _Common {\n  Object get x;\n\n  // x has type int\n  void one(int x);\n\n  // x has type String\n  void one(String x);\n\n  // x has type Object\n  void three();\n}\n```\n\ncommon fields also works with other constructs of dart_sealed like generics and @WithType. for example:\n\n```dart\n@Sealed()\nabstract class _Common {\n  @WithType('num')\n  dynamic get x; // you can omit dynamic\n\n  // x has type int\n  void one(@WithType('int') dynamic x); // you can omit dynamic\n\n  // x has type num\n  void two();\n}\n```\n\nand, for example:\n\n```dart\n@Sealed()\nabstract class _Result\u003cD extends num\u003e {\n  Object? get value;\n\n  void success(D value);\n\n  void error();\n}\n```\n\n## Ignoring Generated Files\n\nIt is recommended to ignore generated files on Git. Add this to your `.gitignore` file:\n\n```\n*.sealed.dart\n```\n\nTo exclude generated files from dart analysis, add this to your `analysis_options.yaml` file:\n\n```\nanalyzer:\n  exclude:\n    - lib/**/*.sealed.dart\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F6thsolution%2Fdart_sealed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F6thsolution%2Fdart_sealed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F6thsolution%2Fdart_sealed/lists"}