'In Dart, syntactically nice way to cast dynamic to given type or return null?
I have a dynamic x and I would like to assign x to T s if x is T, and otherwise assign null to s. Specifically, I would like to avoid having to type x twice, and to avoid creating a temporary. (For example, I don't want to have to write String s = map['key'] is String ? map['key'] : null; over and over, because I will have many such expressions.) I don't want there to be any possibility of a runtime error.
The following works:
class Cast<T> {
T f(x) {
if (x is T) {
return x;
} else {
return null;
}
}
}
// ...
dynamic x = something();
String s = Cast<String>().f(x);
Is there a syntactically nicer way to do this?
Solution 1:[1]
I use the following utility function, which allows for an optional fallback value and error logging.
T tryCast<T>(dynamic x, {T fallback}){
try{
return (x as T);
}
on CastError catch(e){
print('CastError when trying to cast $x to $T!');
return fallback;
}
}
var x = something();
String s = tryCast(x, fallback: 'nothing');
Solution 2:[2]
Just use the as keyword
final tweet = tweets[index] as Tweet;
Solution 3:[3]
I'm using those with Dart null safety (Dart SDK >= 2.12):
T? castOrNull<T>(dynamic x) => x is T ? x : null;
T castOrFallback<T>(dynamic x, T fallback) => x is T ? x : fallback;
Solution 4:[4]
A combination of both prior two posts, without the logging.
Fallback defaults to null when not provided.
T cast<T>(dynamic x, {T fallback}) => x is T ? x : fallback;
Solution 5:[5]
CastError is deprecated, Instead use TypeError.
With null safety, you can try the below snippet. Where fallback is optional/nullable.
T? tryCast<T>(dynamic value, {T? fallback}) {
try {
return (value as T);
} on TypeError catch (_) {
return fallback;
}
}
Or without fallback -
T? tryCast<T>(dynamic value) {
try {
return (value as T);
} on TypeError catch (_) {
return null;
}
}
Usage -
final val = tryCast<String>(1) ?? "";
Solution 6:[6]
This hidden gem was provided by one of Dart-Lang's maintainers:
extension AsExtension on Object? {
X as<X>() => this as X;
X? asOrNull<X>() {
var self = this;
return self is X ? self : null;
}
}
extension AsSubtypeExtension<X> on X {
Y asSubtype<Y extends X>() => this as Y;
}
extension AsNotNullExtension<X> on X? {
X asNotNull() => this as X;
}
// example
void main() {
num? n = 1 as dynamic;
n.as<int>().isEven;
n.asSubtype<int>().isEven; // `n.asSubtype<String>()` is an error.
n.asNotNull().floor();
n.asOrNull<int>()?.isEven; // Corresponds to `(n as? int)?.isEven`.
}
NOTE: If your object is of type dynamic, you have to cast it Object? first. The explanation for this can be found here: first one by Erik, a dart maintainer @Google and the second by a community member. Basically it boils down to dart not calling extension methods on receives of one of the following three types: dynamic, Never, or void as stated here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | dave o grady |
| Solution 3 | MatPag |
| Solution 4 | Ryan Huebert |
| Solution 5 | |
| Solution 6 |
