Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com> Reviewed-on: #3
list_or
Ever worked with an API that usually returns a list of items, but sometimes decides to return a single item just to keep you on your toes?
list_or is a lightweight Dart utility that fixes this exact headache. It takes an arbitrary dynamic value, whether it's a single object, an array, a Set, or even null, and normalizes it into a standard, predictable List<T>.
No more writing boilerplate type-checks for every flexible JSON payload.
Features
- Normalizes inputs: Wraps single values into a list, or passes through existing iterables.
- Fully mutable: Implements
ListMixin, meaning you can.add(),.map(),.remove(), and iterate over it just like any other Dart list. - Type-safe: Strictly enforces your generic type
T. If you expect aStringand get anint, it throws immediately. - Smart null handling: Explicitly supports
nullvalues only if you define the type as nullable (e.g.,ListOr<String?>). - Clean stringification: If the list only has one item,
toString()prints just that item instead of adding[ ]brackets.
Getting Started
Add the package to your pubspec.yaml:
dart pub add list_or
Or, if you're using Flutter:
flutter pub add list_or
Import it in your file:
import 'package:list_or/list_or.dart';
Usage
The most common use case is parsing unpredictable JSON.
Imagine an API endpoint where the tags field might be a single string or an array of strings depending on how many tags the user added.
import 'package:list_or/list_or.dart';
void main() {
// Scenario A: The API returns a single string
final Map<String, dynamic> json1 = {'id': 1, 'tags': 'flutter'};
// Scenario B: The API returns an array of strings
final Map<String, dynamic> json2 = {'id': 2, 'tags': ['dart', 'backend']};
// ListOr normalizes both seamlessly.
final tags1 = ListOr<String>(json1['tags']);
final tags2 = ListOr<String>(json2['tags']);
print(tags1); // Output: flutter
print(tags2); // Output: [dart, backend]
// You can interact with it exactly like a normal list
tags1.add('mobile');
print(tags1.length); // Output: 2
print(tags1.contains('mobile')); // Output: true
}
Handling Nulls
If your payload might intentionally contain nulls, just make your generic type nullable:
// This works perfectly
final nullableList = ListOr<int?>(null);
print(nullableList.length); // Output: 1
// This will throw an ArgumentError to keep your types safe
final strictList = ListOr<int>(null);
Additional Information
- Found a bug? Open an issue on the issue tracker.
- Want to contribute? Pull requests are welcome. Please ensure that all existing tests pass and add new tests for any new functionality.