{"id":13552447,"url":"https://github.com/felangel/equatable","last_synced_at":"2025-05-14T00:09:19.134Z","repository":{"id":33966353,"uuid":"164335859","full_name":"felangel/equatable","owner":"felangel","description":"A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode.","archived":false,"fork":false,"pushed_at":"2024-11-21T18:13:52.000Z","size":450,"stargazers_count":1007,"open_issues_count":4,"forks_count":110,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-03T08:13:00.525Z","etag":null,"topics":["dart","dartlang","equality","equality-comparison","flutter","flutter-package","hashcode","identity"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/equatable","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/felangel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["felangel"]}},"created_at":"2019-01-06T18:51:24.000Z","updated_at":"2025-05-02T11:35:29.000Z","dependencies_parsed_at":"2024-08-01T12:20:47.443Z","dependency_job_id":"011fa62a-e5b7-4731-8c8e-c9a23876e3d2","html_url":"https://github.com/felangel/equatable","commit_stats":{"total_commits":118,"total_committers":22,"mean_commits":5.363636363636363,"dds":0.211864406779661,"last_synced_commit":"ecfe98df1d9063123b660a152d3c5885f1fd121e"},"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felangel%2Fequatable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felangel%2Fequatable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felangel%2Fequatable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felangel%2Fequatable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felangel","download_url":"https://codeload.github.com/felangel/equatable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254044127,"owners_count":22005080,"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":["dart","dartlang","equality","equality-comparison","flutter","flutter-package","hashcode","identity"],"created_at":"2024-08-01T12:02:04.115Z","updated_at":"2025-05-14T00:09:14.121Z","avatar_url":"https://github.com/felangel.png","language":"Dart","funding_links":["https://github.com/sponsors/felangel"],"categories":["Dart"],"sub_categories":[],"readme":"\u003cimg src=\"https://github.com/felangel/equatable/raw/master/doc/assets/equatable_logo_full.png\" width=\"100%\" alt=\"logo\" /\u003e\n\u003ch2 align=\"center\"\u003e\n  Simplify Equality Comparisons\n\u003c/h2\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/felangel/equatable/actions\"\u003e\n    \u003cimg alt=\"Build Status\" src=\"https://github.com/felangel/equatable/workflows/build/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/felangel/equatable/actions\"\u003e\n    \u003cimg alt=\"Code Coverage\" src=\"https://raw.githubusercontent.com/felangel/equatable/master/coverage_badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pub.dartlang.org/packages/equatable\"\u003e\n    \u003cimg alt=\"Pub Package\" src=\"https://img.shields.io/pub/v/equatable.svg\"\u003e\n  \u003c/a\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://github.com/felangel/equatable\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/felangel/equatable.svg?style=flat\u0026logo=github\u0026colorB=deeppink\u0026label=stars\" alt=\"Star on GitHub\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://discord.gg/Hc5KD3g\"\u003e\n    \u003cimg src=\"https://img.shields.io/discord/649708778631200778.svg?logo=discord\u0026color=blue\" alt=\"Discord\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n    \u003cimg alt=\"MIT License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Overview\n\nBeing able to compare objects in `Dart` often involves having to override the `==` operator as well as `hashCode`.\n\nNot only is it verbose and tedious, but failure to do so can lead to inefficient code which does not behave as we expect.\n\nBy default, `==` returns true if two objects are the same instance.\n\nLet's say we have the following class:\n\n```dart\nclass Person {\n  const Person(this.name);\n\n  final String name;\n}\n```\n\nWe can create instances of `Person` like so:\n\n```dart\nvoid main() {\n  final Person bob = Person(\"Bob\");\n}\n```\n\nLater if we try to compare two instances of `Person` either in our production code or in our tests we will run into a problem.\n\n```dart\nprint(bob == Person(\"Bob\")); // false\n```\n\nFor more information about this, you can check out the official [Dart Documentation](https://www.dartlang.org/guides/language/effective-dart/design#equality).\n\nIn order to be able to compare two instances of `Person` we need to change our class to override `==` and `hashCode` like so:\n\n```dart\nclass Person {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  bool operator ==(Object other) =\u003e\n    identical(this, other) ||\n    other is Person \u0026\u0026\n    runtimeType == other.runtimeType \u0026\u0026\n    name == other.name;\n\n  @override\n  int get hashCode =\u003e name.hashCode;\n}\n```\n\nNow if we run the following code again:\n\n```dart\nprint(bob == Person(\"Bob\")); // true\n```\n\nit will be able to compare different instances of `Person`.\n\nYou can see how this can quickly become a hassle when dealing with complex classes. This is where `Equatable` comes in!\n\n## What does Equatable do?\n\n`Equatable` overrides `==` and `hashCode` for you so you don't have to waste your time writing lots of boilerplate code.\n\nThere are other packages that will actually generate the boilerplate for you; however, you still have to run the code generation step which is not ideal.\n\nWith `Equatable` there is no code generation needed and we can focus more on writing amazing applications and less on mundane tasks.\n\n## Usage\n\nFirst, we need to do add `equatable` to the dependencies of the `pubspec.yaml`\n\n```yaml\ndependencies:\n  equatable: ^2.0.0\n```\n\nNext, we need to install it:\n\n```sh\n# Dart\npub get\n\n# Flutter\nflutter packages get\n```\n\nLastly, we need to extend `Equatable`\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  List\u003cObject\u003e get props =\u003e [name];\n}\n```\n\nWhen working with json:\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  List\u003cObject\u003e get props =\u003e [name];\n\n  factory Person.fromJson(Map\u003cString, dynamic\u003e json) {\n    return Person(json['name']);\n  }\n}\n```\n\nWe can now compare instances of `Person` just like before without the pain of having to write all of that boilerplate.\n**Note:** Equatable is designed to only work with immutable objects so all member variables must be final (This is not just a feature of `Equatable` - [overriding a `hashCode` with a mutable value can break hash-based collections](https://dart.dev/guides/language/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes)).\n\nEquatable also supports `const` constructors:\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  List\u003cObject\u003e get props =\u003e [name];\n}\n```\n\nEquatable also supports nullable props:\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name, [this.age]);\n\n  final String name;\n  final int? age;\n\n  @override\n  List\u003cObject?\u003e get props =\u003e [name, age];\n}\n```\n\n### `toString` Implementation\n\nEquatable can implement `toString` method including all the given props. If you want that behaviour for a specific `Equatable` object, just include the following:\n\n```dart\n@override\nbool get stringify =\u003e true;\n```\n\nFor instance:\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  List\u003cObject\u003e get props =\u003e [name];\n\n  @override\n  bool get stringify =\u003e true;\n}\n```\n\nFor the name `Bob`, the output will be:\n\n`Person(Bob)`\n\nThis flag by default is false and `toString` will return just the type:\n\n`Person`\n\n#### EquatableConfig\n\n`stringify` can also be configured globally for all `Equatable` instances via `EquatableConfig`\n\n```dart\nEquatableConfig.stringify = true;\n```\n\nIf `stringify` is overridden for a specific `Equatable` class, then the value of `EquatableConfig.stringify` is ignored.\nIn other words, the local configuration always takes precedence over the global configuration.\n\n_Note: `EquatableConfig.stringify` defaults to `true` in debug mode and `false` in release mode._\n\n## Recap\n\n### Without Equatable\n\n```dart\nclass Person {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  bool operator ==(Object other) =\u003e\n    identical(this, other) ||\n    other is Person \u0026\u0026\n    runtimeType == other.runtimeType \u0026\u0026\n    name == other.name;\n\n  @override\n  int get hashCode =\u003e name.hashCode;\n}\n```\n\n### With Equatable\n\n```dart\nimport 'package:equatable/equatable.dart';\n\nclass Person extends Equatable {\n  const Person(this.name);\n\n  final String name;\n\n  @override\n  List\u003cObject\u003e get props =\u003e [name];\n}\n```\n\n## EquatableMixin\n\nSometimes it isn't possible to extend `Equatable` because your class already has a superclass.\nIn this case, you can still get the benefits of `Equatable` by using the `EquatableMixin`.\n\n### Usage\n\nLet's say we want to make an `EquatableDateTime` class, we can use `EquatableMixin` like so:\n\n```dart\nclass EquatableDateTime extends DateTime with EquatableMixin {\n  EquatableDateTime(\n    int year, [\n    int month = 1,\n    int day = 1,\n    int hour = 0,\n    int minute = 0,\n    int second = 0,\n    int millisecond = 0,\n    int microsecond = 0,\n  ]) : super(year, month, day, hour, minute, second, millisecond, microsecond);\n\n  @override\n  List\u003cObject\u003e get props {\n    return [year, month, day, hour, minute, second, millisecond, microsecond];\n  }\n}\n```\n\nNow if we want to create a subclass of `EquatableDateTime`, we can just override `props`.\n\n```dart\nclass EquatableDateTimeSubclass extends EquatableDateTime {\n  final int century;\n\n  EquatableDateTimeSubclass(\n    this.century,\n    int year,[\n    int month = 1,\n    int day = 1,\n    int hour = 0,\n    int minute = 0,\n    int second = 0,\n    int millisecond = 0,\n    int microsecond = 0,\n  ]) : super(year, month, day, hour, minute, second, millisecond, microsecond);\n\n  @override\n  List\u003cObject\u003e get props =\u003e [...super.props, century];\n}\n```\n\n## Benchmarks\n\nYou can see and run performance benchmarks by heading over to [benchmarks](./benchmarks).\n\n## Maintainers\n\n- [Felix Angelov](https://github.com/felangel)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelangel%2Fequatable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelangel%2Fequatable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelangel%2Fequatable/lists"}