letOrNull<T> function

T? letOrNull<T>(
  1. dynamic input
)

Attempts to convert a dynamic input to the specified type T, returning Null on failure.

This is a high-level dispatcher that uses more specific let...OrNull helpers based on the target type T.

Supported types:

Implementation

T? letOrNull<T>(dynamic input) {
  // Enforced in release as well: a stripped assert would let a misuse like
  // `letOrNull<List<int>>(...)` silently return null, which is
  // indistinguishable from a real conversion failure. For medical-grade
  // code that's an unacceptable silent failure.
  if ((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>())) {
    throw ArgumentError(
      'letOrNull<$T> cannot be used with specific collection types due to '
      'type safety. Only the broadest collection types '
      '(Iterable<dynamic>, Map<dynamic, dynamic>) are supported.',
    );
  }
  if (input is T) return input;
  if (input == null) return null;
  final raw = () {
    if (typeEquality<T, double>() || typeEquality<T, double?>()) {
      return letDoubleOrNull(input);
    } else if (typeEquality<T, int>() || typeEquality<T, int?>()) {
      return letIntOrNull(input);
    } else if (typeEquality<T, bool>() || typeEquality<T, bool?>()) {
      return letBoolOrNull(input);
    } else if (typeEquality<T, DateTime>() || typeEquality<T, DateTime?>()) {
      return letDateTimeOrNull(input);
    } else if (typeEquality<T, Uri>() || typeEquality<T, Uri?>()) {
      return letUriOrNull(input);
    } else if (isSubtype<T, List<dynamic>>()) {
      return letListOrNull<dynamic>(input);
    } else if (isSubtype<T, Set<dynamic>>()) {
      return letSetOrNull<dynamic>(input);
    } else if (isSubtype<T, Iterable<dynamic>>()) {
      return letIterableOrNull<dynamic>(input);
    } else if (isSubtype<T, Map<dynamic, dynamic>>()) {
      return letMapOrNull<dynamic, dynamic>(input);
    } else if (typeEquality<T, String>() || typeEquality<T, String?>()) {
      return letAsStringOrNull(input);
    }
    return input;
  }();

  return letAsOrNull<T>(raw);
}