Skip to content

Instantly share code, notes, and snippets.

@sma
Created December 14, 2020 18:11
Show Gist options
  • Save sma/e77d28237678de05b0a8406c88ae092d to your computer and use it in GitHub Desktop.
Save sma/e77d28237678de05b0a8406c88ae092d to your computer and use it in GitHub Desktop.
a typesafe wrapper for accessing json
class Json extends Iterable<Json> {
Json(this.value);
Json.from(String s) : this(jsonDecode(s));
final dynamic value;
@override
String toString() => jsonEncode(value);
bool get isNull => value == null;
bool get isBool => value is bool;
bool get isNum => value is num;
bool get isInt => value is int;
bool get isDouble => value is double;
bool get isString => value is String;
bool get isArray => value is List;
bool get isObject => value is Map;
bool get asBool => value as bool;
num get asNum => value as num;
int get asInt => asNum.toInt();
double get asDouble => asNum.toDouble();
String get asString => value as String;
List<Json> get asArray => (value as List).map((e) => Json(e)).toList();
Map<String, Json> get asObject => (value as Map).map((k, v) => MapEntry(k, Json(v)));
bool? get optBool => value as bool?;
num? get optNum => value as num?;
int? get optInt => optNum?.toInt();
double? get optDouble => optNum?.toDouble();
String? get optString => value as String?;
List<Json>? get optArray => (value as List?)?.map((e) => Json(e)).toList();
Map<String, Json>? get optObject => (value as Map?)?.map((k, v) => MapEntry(k, Json(v)));
/// Returns the JSON value at [key] which must be either an `int` or a `String`, depending
/// on whether the receiver is an array or an object. If the receiver is `null`, `null` is
/// returned and the [key] is ignored. If the [key] doesn't exist, `Json(null)` is returned.
Json operator [](dynamic key) {
if (value == null) return this;
if (value is List) {
final index = (key as num).toInt();
return Json(index >= 0 && index < value.length ? value[index] : null);
}
if (value is Map<String, dynamic>) return Json(value[key.toString()]);
throw TypeError();
}
@override
Iterator<Json> get iterator => asArray.iterator;
/// Creates a instance of [T] by applying [decode] to the receiver.
/// If the receiver is `null`, `null` is returned.
/// The [decode] function should throw a [TypeError] is something doesn't match.
T? of<T>(T Function(Json) decode) => isNull ? null : decode(value);
/// Creates a list of instances of [T] by applying [decode] to all array elements if the receiver is an array.
/// If the receiver is `null`, `null` is returned.
/// If the receiver isn't an array and isn't `null`, a [TypeError] is thrown.
/// The [decode] function should throw a [TypeError] is something doesn't match.
List<T>? mapOf<T>(T Function(Json) decode) => (value as List?)?.map((e) => decode(Json(e))).toList();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment