zeba_academy_nullable
A lightweight, dependency-free collection of generic nullable-value utilities for Dart and Flutter.
zeba_academy_nullable provides convenient helpers for fallback values, nullable transformations, conditional execution, filtering, first-non-null selection, and other null-safe operations while working naturally with Dart's built-in null-safety system.
Features
- ✅ Generic nullable-value utilities
- ✅ Fallback values
- ✅ Lazy fallback evaluation
- ✅ Nullable transformations
- ✅ Transformations with fallback values
- ✅ Conditional execution
- ✅ Null-only execution
- ✅ Conditional value selection
- ✅ Nullable filtering
- ✅ First non-null value selection
- ✅ Generic
foldoperations - ✅ Convenient extension methods
- ✅ Fully null-safe
- ✅ No runtime dependencies
- ✅ Lightweight and easy to integrate
- ✅ Works with Dart and Flutter
- ✅ Suitable for production applications
Installation
Add zeba_academy_nullable to your pubspec.yaml:
dependencies:
zeba_academy_nullable: ^0.0.1
Then run:
flutter pub get
For Dart-only projects:
dart pub get
Import
import 'package:zeba_academy_nullable/zeba_academy_nullable.dart';
Quick Start
Fallback values
Use valueOr when you want a fallback value when the original value is null.
String? username;
final displayName = username.valueOr('Guest');
print(displayName);
Output:
Guest
When the value is not null, the original value is returned:
String? username = 'Sarvesh';
final displayName = username.valueOr('Guest');
print(displayName);
Output:
Sarvesh
Lazy fallback values
Use valueOrElse when calculating the fallback may be expensive.
String? token;
final value = token.valueOrElse(
() => generateDefaultToken(),
);
The fallback callback is only executed when the value is null.
Nullable transformations
Use mapNullable to transform a nullable value without manually checking for null.
String? name = 'Sarvesh';
final length = name.mapNullable(
(value) => value.length,
);
print(length);
Output:
7
When the value is null:
String? name;
final length = name.mapNullable(
(value) => value.length,
);
print(length);
Output:
null
Transform with a fallback
Use mapOr when you want a fallback result.
String? ageText;
final age = ageText.mapOr(
(value) => int.parse(value),
0,
);
print(age);
Output:
0
For a non-null value:
String? ageText = '25';
final age = ageText.mapOr(
(value) => int.parse(value),
0,
);
print(age);
Output:
25
Lazy transformation fallback
Use mapOrElse when the fallback result should be calculated only when needed.
String? value;
final result = value.mapOrElse(
(value) => value.length,
() => calculateDefaultLength(),
);
The fallback callback is not executed when value is non-null.
Execute only for non-null values
Use runIfNotNull when you want to perform an action only when a value exists.
String? username = 'Sarvesh';
username.runIfNotNull(
(value) {
print('Hello $value');
},
);
Output:
Hello Sarvesh
For a null value, the callback is not executed.
Execute only when null
Use ifNull when you need to perform an action only when a value is missing.
String? profileImage;
profileImage.ifNull(() {
print('Show default profile image');
});
First non-null value
firstNotNull returns the first available non-null value.
final value = NullableUtils.firstNotNull<String>([
null,
null,
'Flutter',
'Dart',
]);
print(value);
Output:
Flutter
If every value is null, the result is null.
final value = NullableUtils.firstNotNull<String>([
null,
null,
null,
]);
print(value);
Output:
null
First non-null value with fallback
Use firstNotNullOr when you always need a non-null result.
final apiUrl = NullableUtils.firstNotNullOr<String>(
[
null,
null,
'https://example.com',
],
'https://default.example.com',
);
print(apiUrl);
Null checks
You can explicitly check nullable values using:
NullableUtils.isNull(value);
and:
NullableUtils.isNotNull(value);
Example:
String? username;
if (NullableUtils.isNull(username)) {
print('Username is missing');
}
Or:
String? username = 'Sarvesh';
if (NullableUtils.isNotNull(username)) {
print('Username is available');
}
Conditional values
Use takeIf when a value should only be retained when a condition is true.
final result = NullableUtils.takeIf(
'Flutter',
true,
);
print(result);
Output:
Flutter
When the condition is false:
final result = NullableUtils.takeIf(
'Flutter',
false,
);
print(result);
Output:
null
Predicate-based selection
Use takeIfOrNull when the condition depends on the value itself.
final result = NullableUtils.takeIfOrNull(
100,
(value) => value > 50,
);
print(result);
Output:
100
If the predicate fails:
final result = NullableUtils.takeIfOrNull(
100,
(value) => value > 200,
);
print(result);
Output:
null
Nullable filtering
Use where to keep a nullable value only when it satisfies a predicate.
final result = NullableUtils.where(
10,
(value) => value.isEven,
);
print(result);
Output:
10
Example where the predicate fails:
final result = NullableUtils.where(
11,
(value) => value.isEven,
);
print(result);
Output:
null
The extension equivalent is:
final result = 10.where(
(value) => value.isEven,
);
Conditional conversion
Use convertIf when you want to transform a value only when a condition is satisfied.
final result = NullableUtils.convertIf(
10,
(value) => value > 5,
(value) => 'Value: $value',
);
print(result);
Output:
Value: 10
If the condition fails, null is returned.
Fold nullable values
fold lets you explicitly handle both cases.
String? username;
final message = username.fold(
onValue: (value) => 'Welcome $value',
onNull: () => 'Welcome Guest',
);
print(message);
Output:
Welcome Guest
With a value:
String? username = 'Sarvesh';
final message = username.fold(
onValue: (value) => 'Welcome $value',
onNull: () => 'Welcome Guest',
);
print(message);
Output:
Welcome Sarvesh
API Reference
NullableUtils
valueOr
static T valueOr<T>(
T? value,
T fallback,
)
Returns value when non-null, otherwise returns fallback.
valueOrElse
static T valueOrElse<T>(
T? value,
T Function() fallback,
)
Returns value when non-null, otherwise lazily evaluates fallback.
firstNotNull
static T? firstNotNull<T>(
Iterable<T?> values,
)
Returns the first non-null value.
Returns null when all values are null.
firstNotNullOr
static T firstNotNullOr<T>(
Iterable<T?> values,
T fallback,
)
Returns the first non-null value or the supplied fallback.
isNull
static bool isNull<T>(T? value)
Returns true when the value is null.
isNotNull
static bool isNotNull<T>(T? value)
Returns true when the value is not null.
map
static R? map<T, R>(
T? value,
R Function(T value) transform,
)
Transforms a non-null value and returns null for a null input.
mapOr
static R mapOr<T, R>(
T? value,
R Function(T value) transform,
R fallback,
)
Transforms a value or returns a fallback.
mapOrElse
static R mapOrElse<T, R>(
T? value,
R Function(T value) transform,
R Function() fallback,
)
Transforms a value or lazily computes a fallback.
runIfNotNull
static T? runIfNotNull<T>(
T? value,
void Function(T value) action,
)
Runs an action only when the value is non-null.
ifNull
static T? ifNull<T>(
T? value,
void Function() action,
)
Runs an action only when the value is null.
takeIf
static T? takeIf<T>(
T value,
bool condition,
)
Returns the value when the condition is true.
takeIfOrNull
static T? takeIfOrNull<T>(
T value,
bool Function(T value) predicate,
)
Returns the value when the predicate succeeds.
convertIf
static R? convertIf<T, R>(
T? value,
bool Function(T value) condition,
R Function(T value) convert,
)
Conditionally converts a nullable value.
let
static R? let<T, R>(
T? value,
R? Function(T value) transform,
)
Applies a transformation only when the value is non-null.
where
static T? where<T>(
T? value,
bool Function(T value) predicate,
)
Keeps a nullable value when the predicate succeeds.
nullable
static T? nullable<T>(
T? value,
)
Explicitly preserves a nullable value.
fold
static R fold<T, R>(
T? value, {
required R Function(T value) onValue,
required R Function() onNull,
})
Handles both nullable and non-null cases.
Extension API
The package also provides:
extension NullableValueExtension<T> on T?
Available extension methods:
valueOr()
valueOrElse()
mapNullable()
mapOr()
mapOrElse()
runIfNotNull()
ifNull()
takeIf()
takeIfOrNull()
where()
fold()
This allows concise syntax such as:
final result = username
.mapNullable((value) => value.trim())
.mapOr(
(value) => value.toUpperCase(),
'UNKNOWN',
);
Generic Usage
The utilities work with custom types as well.
class User {
final String name;
const User(this.name);
}
You can write:
User? user;
final name = user.mapNullable(
(value) => value.name,
);
Or:
final displayName = user.mapOr(
(value) => value.name,
'Guest',
);
No special model classes or wrappers are required.
Flutter Example
The package can be useful inside Flutter widgets and ViewModels.
class ProfileViewModel {
String? username;
String? profileImage;
String get displayName {
return username.valueOr('Guest');
}
String get imageUrl {
return profileImage.valueOr(
'assets/images/default_profile.png',
);
}
}
Another example:
Text(
user?.name.valueOr('Unknown') ?? 'Unknown',
)
For more complex transformations:
final displayName = user?.name.mapOr(
(value) => value.trim().isEmpty
? 'Unknown'
: value,
'Unknown',
);
Design Philosophy
zeba_academy_nullable is intentionally small.
The package does not introduce another nullable abstraction such as:
Option<T>
Some<T>
None<T>
Maybe<T>
Nullable<T>
Instead, it works directly with Dart's native:
T?
This keeps the package:
- Simple
- Familiar
- Lightweight
- Generic
- Easy to adopt
- Compatible with existing Dart code
For explicit Some/None style programming, a dedicated optional-value abstraction is more appropriate.
Dependencies
This package has zero runtime dependencies.
It relies only on Dart's standard language and null-safety features.
Compatibility
The package is designed for modern Dart and Flutter projects.
environment:
sdk: ">=3.12.0 <4.0.0"
flutter: ">=1.17.0"
Testing
The package includes comprehensive unit tests covering:
- Fallback values
- Lazy fallbacks
- Nullable transformations
- Transformation fallbacks
- Conditional execution
- Null execution
- First non-null selection
- Conditional filtering
- Conditional conversion
- Fold operations
- Extension methods
- Generic behavior
Run the test suite with:
flutter test
Static Analysis
Run:
flutter analyze
The package is intended to maintain a clean analyzer result before every release.
Formatting
Format the package with:
dart format lib test
Publishing
Before publishing to pub.dev, run:
flutter pub publish --dry-run
If everything is correct:
flutter pub publish
Contributing
Contributions are welcome.
Before submitting a pull request:
- Keep APIs generic and null-safe.
- Avoid unnecessary dependencies.
- Add tests for new functionality.
- Run
dart format. - Run
flutter analyze. - Run
flutter test. - Update documentation when public APIs change.
- Keep the package focused on nullable-value utilities.
License
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
See the LICENSE file for the complete license text.
About Me
✨ I’m Sufyan bin Uzayr, an open-source developer passionate about building and sharing meaningful projects.
You can learn more about me and my work at sufyanism.com or connect with me on LinkedIn.
Your All-in-One Learning Hub!
🚀 Explore courses and resources in coding, tech, and development at Zeba Academy.
Empower yourself with practical skills through curated tutorials, real-world projects, and hands-on experience. Level up your tech game today! 💻✨
Zeba Academy is a learning platform dedicated to coding, technology, and development.
➡ Visit the main site: zeba.academy
➡ Explore hands-on courses and resources: code.zeba.academy
➡ Check out the YouTube channel for more tutorials: Zeba Academy on YouTube
➡ Follow on Instagram: Zeba Academy on Instagram
Thank You
Thank you for visiting and supporting this project! ❤️
If you find zeba_academy_nullable useful, consider giving the project a star, sharing it with other Dart and Flutter developers, and contributing to the open-source community.
Built with ❤️ for the Dart & Flutter community.