letOrNone<T extends Object> function
Attempts to convert a dynamic input
to the specified type T
, returning
None on failure.
This is a high-level dispatcher that uses more specific let...OrNone
helpers based on the target type T
.
Supported types:
Implementation
Option<T> letOrNone<T extends Object>(dynamic input) {
assert(
!(isSubtype<T, List<dynamic>>() && !isSubtype<List<dynamic>, T>()) &&
!(isSubtype<T, Set<dynamic>>() && !isSubtype<Set<dynamic>, T>()) &&
!(isSubtype<T, Iterable<dynamic>>() &&
!isSubtype<Iterable<dynamic>, T>()) &&
!(isSubtype<T, Map<dynamic, dynamic>>() &&
!isSubtype<Map<dynamic, dynamic>, T>()),
'letOrNone<$T> cannot be used with specific collection types due to type safety. '
'Only generic collection types are supported.',
);
// 1. Unwrap any Outcome to get the raw value.
if (input is Outcome) {
return switch (input.rawSync().value) {
Ok(value: final okValue) => letOrNone<T>(NoStackOverflowWrapper(okValue)),
Err() => const None(),
};
}
final rawInput = input is NoStackOverflowWrapper ? input.value : input;
// 2. Handle null and direct type matches upfront for performance.
if (rawInput is T) return Some(rawInput);
if (rawInput == null) return const None();
// 3. Dispatch to specific conversion logic based on the target type.
final result = () {
if (typeEquality<T, double>() || typeEquality<T, double?>()) {
return letDoubleOrNone(rawInput);
} else if (typeEquality<T, int>() || typeEquality<T, int?>()) {
return letIntOrNone(rawInput);
} else if (typeEquality<T, bool>() || typeEquality<T, bool?>()) {
return letBoolOrNone(rawInput);
} else if (typeEquality<T, DateTime>() || typeEquality<T, DateTime?>()) {
return letDateTimeOrNone(rawInput);
} else if (typeEquality<T, Uri>() || typeEquality<T, Uri?>()) {
return letUriOrNone(rawInput);
} else if (isSubtype<T, List<dynamic>>()) {
return letListOrNone<Object>(rawInput);
} else if (isSubtype<T, Set<dynamic>>()) {
return letSetOrNone<Object>(rawInput);
} else if (isSubtype<T, Iterable<dynamic>>()) {
return letIterableOrNone<Object>(rawInput);
} else if (isSubtype<T, Map<dynamic, dynamic>>()) {
return letMapOrNone<Object, Object>(rawInput);
} else if (typeEquality<T, String>() || typeEquality<T, String?>()) {
return letAsStringOrNone(rawInput);
}
return rawInput;
}();
// 4. Perform a final safe cast on the result of the conversion.
return letAsOrNone<T>(result);
}