letOrNull<T> function
T?
letOrNull<T>(
- 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 (each also in its nullable form, e.g. int?):
- bool
- num
- double
- int
- String
- DateTime
- Uri,
- Iterable (dynamic)
- List (dynamic)
- Set (dynamic)
- Map (dynamic, dynamic)
If input already is a T, it is returned unchanged, whatever T is.
A null input returns null.
Throws ArgumentError when input would need converting into a type this
dispatcher cannot produce, rather than returning a null that looks like
an ordinary conversion failure:
- Specific collection types such as
List<int>orMap<String, int>. Use letListOrNull, letSetOrNull, letIterableOrNull or letMapOrNull with the element types instead. - Enums. An enum value cannot be found from the type alone. Look it up
by name with
MyEnum.values.valueOf(...)(returnsnullon a miss) orMyEnum.values.valueOfOrThrow(...).
Implementation
T? letOrNull<T>(dynamic input) {
if (input is T) return input;
if (input == null) return null;
// Enforced in release as well: a stripped assert would let a misuse like
// `letOrNull<List<int>>('[1]')` silently return null, which is
// indistinguishable from a real conversion failure. For medical-grade
// code that's an unacceptable silent failure.
if (_isSpecificCollectionType<T>()) {
throw ArgumentError(
'letOrNull<$T> cannot convert a ${input.runtimeType} into a specific '
'collection type. Only List<dynamic>, Set<dynamic>, Iterable<dynamic> '
'and Map<dynamic, dynamic> (or their nullable forms) are converted; use '
'letListOrNull, letSetOrNull, letIterableOrNull or letMapOrNull with '
'the element types instead.',
);
}
if (_isEnumType<T>()) {
throw ArgumentError(
'letOrNull<$T> cannot convert a ${input.runtimeType} into an enum. '
'Look the value up by name with $T.values.valueOf(...) or '
'$T.values.valueOfOrThrow(...) instead.',
);
}
final raw = () {
if (typeEquality<T, num>() || typeEquality<T, num?>()) {
return letNumOrNull(input);
} else 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);
}