{"id":16754313,"url":"https://github.com/purplenoodlesoop/typed-preferences","last_synced_at":"2026-03-13T20:34:32.051Z","repository":{"id":62459016,"uuid":"518986006","full_name":"purplenoodlesoop/typed-preferences","owner":"purplenoodlesoop","description":"💾 Expressive and type-safe wrapper around Shared Preferences with additional features like Observers and DAOs.","archived":false,"fork":false,"pushed_at":"2022-12-02T18:08:01.000Z","size":30,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T14:05:27.779Z","etag":null,"topics":["dao","dao-design-pattern","dart","flutter","sharedpreferences","typesafe"],"latest_commit_sha":null,"homepage":"","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/purplenoodlesoop.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}},"created_at":"2022-07-28T20:29:25.000Z","updated_at":"2024-09-18T17:00:12.000Z","dependencies_parsed_at":"2023-01-23T08:45:45.799Z","dependency_job_id":null,"html_url":"https://github.com/purplenoodlesoop/typed-preferences","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purplenoodlesoop%2Ftyped-preferences","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purplenoodlesoop%2Ftyped-preferences/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purplenoodlesoop%2Ftyped-preferences/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purplenoodlesoop%2Ftyped-preferences/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purplenoodlesoop","download_url":"https://codeload.github.com/purplenoodlesoop/typed-preferences/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248251506,"owners_count":21072689,"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":["dao","dao-design-pattern","dart","flutter","sharedpreferences","typesafe"],"created_at":"2024-10-13T03:04:33.457Z","updated_at":"2026-03-13T20:34:27.018Z","avatar_url":"https://github.com/purplenoodlesoop.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typed_preferences \n\n[![Pub](https://img.shields.io/pub/v/typed_preferences.svg)](https://pub.dev/packages/typed_preferences)\n[![GitHub Stars](https://img.shields.io/github/stars/purplenoodlesoop/typed-preferences.svg)](https://github.com/purplenoodlesoop/typed-preferences)\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://en.wikipedia.org/wiki/MIT_License)\n[![Linter](https://img.shields.io/badge/style-custom-brightgreen)](https://github.com/purplenoodlesoop/typed-preferences/blob/master/analysis_options.yaml)\n[![Code size](https://img.shields.io/github/languages/code-size/purplenoodlesoop/typed-preferences)](https://github.com/purplenoodlesoop/typed-preferences)\n\n---\n\ntyped_preferences provides a type-safe wrapper around Shared Preferences with additional features like Observers and DAOs.\n\n## Index\n\n- [Index](#index)\n- [Motivation](#motivation)\n- [Usage](#usage)\n    - [Driver](#driver)\n    - [DAOs](#daos)\n    - [Observers](#observers)\n\n## Motivation\n\nShared Preferences are usable as-is and provide an excellent multi-platform experience, but fall short in Safety and Developer Experience. Typed Preferences try to solve those problems by creating a wrapper that exposes concise, expressive, and type-safe API.\n\nTurning this:\n\n```dart\nextension UserKey on Never {\n  static const String name = 'user.name';\n  static const String age = 'user.age';\n}\n```\n\n```dart\nclass UserDao {\n  final SharedPreferences _preferences;\n\n  UserDao(this._preferences);\n\n  String get name =\u003e _preferences.getString(UserKeys.name);\n\n  String get age =\u003e _preferences.getInt(UserKeys.age);\n\n  // Note – you can try to set String and get int, resulting in a runtime type error\n  Future\u003cvoid\u003e setName(String name) =\u003e _preferences.setString(UserKeys.name, name);\n\n  Future\u003cvoid\u003e setAge(int age) =\u003e _preferences.setInt(UserKeys.age, age);\n}\n```\n\nInto this:\n\n```dart\nclass UserDao extends TypedPreferencesDao {\n  UserDao(super.driver);\n\n  // Everything type-safe! Also, the resulting key will be `typed.user.name`\n  PreferencesEntry\u003cString\u003e get name =\u003e stringEntry('name');\n\n  PreferencesEntry\u003cint\u003e get age =\u003e intEntry('age');\n}\n```\n\n## Usage\n\nThe package offers four main actors that are used throughout every interaction: `PreferencesDriver`, `PreferencesDriverObserver`, `TypedPreferencesDao`, and `PreferencesEntry\u003cT\u003e`. Every one of them will be discussed below, but the usage is quite simple – DAOs need Drivers to function, and entries are declared as getters from the DAOs.\n\n### Driver\n\n`PreferencesDriver` is needed by DAOs to operate. It is usually a shared object that is passed to every DAO in the constructor. Besides providing actual \"driver\" functionality, the `PreferencesDriver` is used to set up Observers, which will be discussed later. \n\nSince usually there is only one driver needed, in Flutter application the best place to create one is in the `main()` function. The driver is not stateful and does not require disposal after usage.\n\n```dart\nfinal preferences = await SharedPreferences.getInstance();\n\nfinal driver = PreferencesDriver(\n  sharedPreferences: preferences,\n  observers: const [LoggerPreferencesDriverObserver()],\n);\n\nrunApp(App(driver: driver));\n```\n\n### DAOs\n\nDAOs are used to describe schema-like classes with two-way type-safe entries. To create a DAO, a concrete class should extend the `TypedPreferencesDao` base class and pass a `PreferencesDriver` to a super-constructor. To declare DAOs' entries, any of the following methods are used – `stringEntry`, `intEntry`, `doubleEntry`, `boolEntry`, `stringListEntry`.\n\nThe most simple DAO can look something like that: \n\n```dart\nclass ExampleDao extends TypedPreferencesDao {\n  ExampleDao(super.driver);\n\n  PreferencesEntry\u003cString\u003e get someEntry =\u003e stringEntry('some_key');\n}\n```\n\nA few things are happening behind the scenes:\n  1. Every key passed to the methods is prefixed with `typed.` and the name of the DAO. So, in the case of `someEntry`, the resulting key would be `typed.example.some_key`. The `example` name can be overridden via the `name` getter.\n  2. Entries are cached by key. So, only on the first access to the `someEntry` field the object will be created and written in the cache by the given `some_key`,\n  3. Observers connected to the `PreferencesDriver` will fire on declared entries manipulations.\n\n### Observers\n\nObservers can be created by extending the base class `PreferencesDriverObserver` and connected via the `observers` argument of the `PreferencesDriver`'s constructor. Several methods can be overridden, and the usage can vary – from logging to reactivity.\n\nAn example of a logger-observer can look like the following: \n\n```dart\nclass LoggerPreferencesDriverObserver extends PreferencesDriverObserver {\n  const LoggerPreferencesDriverObserver();\n\n  void _log(void Function(StringBuffer b) logBuilder) {\n    final buffer = StringBuffer('LoggerPreferencesDriverObserver | ');\n    logBuilder(buffer);\n    print(buffer.toString());\n  }\n\n  @override\n  void onSet\u003cT\u003e(String path, T value, bool isSuccess) {\n    super.onSet(path, value, isSuccess);\n    _log(\n      (b) =\u003e b\n        ..write('Set ')\n        ..write(path)\n        ..write(' to value ')\n        ..write(value)\n        ..write(' ')\n        ..write(isSuccess ? 'successfully' : 'unsuccessfully'),\n    );\n  }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurplenoodlesoop%2Ftyped-preferences","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurplenoodlesoop%2Ftyped-preferences","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurplenoodlesoop%2Ftyped-preferences/lists"}