Skip to content

fix(dart): use .cast<T>() for primitive list/map fromJson#1

Merged
tiz-sharp merged 1 commit into
masterfrom
fix/primitive-list-map-cast
Jun 23, 2026
Merged

fix(dart): use .cast<T>() for primitive list/map fromJson#1
tiz-sharp merged 1 commit into
masterfrom
fix/primitive-list-map-cast

Conversation

@tiz-sharp

Copy link
Copy Markdown
Contributor

Problem

jsonDecode (dart:convert) always returns List<dynamic> for JSON arrays and Map<String, dynamic> for objects — it cannot know element types. A generated expr as List<String> therefore throws at runtime (type 'List<dynamic>' is not a subtype of type 'List<String>') even when every element is a String. The same applies to primitive maps.

This broke fromJson for any model with a primitive array. Concretely it crashed the login response (PRPVUserBaseFullLoginResponse.roles), so consumers could not authenticate.

Fix

model_generator now emits the idiomatic, type-safe form:

  • list of primitives → (expr as List).cast<T>()
  • map of primitives → (expr as Map).cast<String, V>()

This matches the convention already used in type_utils.dart (query-param lists). Object/ref/enum list paths are unchanged (they already used List<T>.generate(... fromJson ...)).

Tests

  • Added a regression assertion on the petstore photoUrls (List<String>) field: the generated fromJson must contain (json['photoUrls'] as List).cast<String>() and must NOT contain a naive as List<String>.
  • Full suite green (36 tests).
  • Verified end-to-end: regenerating a real client produced (json['roles'] as List).cast<String>() with zero naive casts remaining across 1015 files; login + downstream calls succeed.

🤖 Generated with Claude Code

… cast)

jsonDecode always yields List<dynamic> / Map<String,dynamic> at runtime, so a
direct `expr as List<String>` (or `as Map<String,T>`) cast throws
"List<dynamic> is not a subtype of List<String>" even when every element matches.
This crashed deserialization of any model with a primitive array — e.g. the login
response `roles` field, breaking authentication in consumers.

model_generator now emits `(expr as List).cast<T>()` and `(expr as Map).cast<K,V>()`,
matching the convention already used in type_utils.dart for query params. Adds a
regression assertion on the petstore `photoUrls` List<String> field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tiz-sharp tiz-sharp merged commit 3d0eb9f into master Jun 23, 2026
1 check passed
@tiz-sharp tiz-sharp deleted the fix/primitive-list-map-cast branch June 23, 2026 23:19
@tiz-sharp tiz-sharp mentioned this pull request Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants