Skip to content

Eliminate all 171 as type casts from lib/ code #41

Description

@MelbourneDeveloper

Problem

The project rules in CLAUDE.md explicitly state as is ILLEGAL. Yet there are 171 as type casts across 20 lib/ files in production code.

These unsafe casts can throw TypeError at runtime with no compile-time safety. Every single one needs to be replaced with pattern matching, extension types, or safe conversion helpers.

Full Inventory

By Package

Package File Cast Count
dart_node_mcp lib/src/mcp_server.dart 49
reflux lib/src/selectors.dart 16
dart_node_vsix lib/src/js_helpers.dart 12
dart_node_react_native lib/src/testing.dart 11
dart_node_better_sqlite3 lib/src/statement.dart 10
dart_node_react lib/src/reducer_hook.dart 10
dart_node_react lib/src/testing_library.dart 9
dart_node_better_sqlite3 lib/src/database.dart 7
dart_node_mcp lib/src/stdio_transport.dart 4
dart_node_react lib/src/state_hook.dart 4
dart_node_react_native lib/src/npm_component.dart 6
dart_node_coverage lib/src/runtime.dart 4
dart_node_react lib/src/ref.dart 3
dart_node_vsix lib/src/tree_view.dart 3
dart_node_vsix lib/src/extension_context.dart 3
dart_node_core lib/src/child_process.dart 2
dart_node_react lib/src/special_components.dart 2
dart_node_mcp lib/src/server.dart 2
dart_node_react lib/src/react.dart 1
dart_node_react lib/src/elements.dart 1
dart_node_react lib/src/test_utils.dart 1
reflux lib/src/enhancers.dart 1
dart_node_vsix lib/src/event_emitter.dart 1

Cast Patterns (what to replace with)

There are 5 distinct patterns. Each needs a different replacement strategy:


Pattern 1: JS property access → JSFunction (70+ occurrences)

Current:

final prepareFn = jsDb['prepare']! as JSFunction;

Replace with: Type-safe extension types with external getters

extension type BetterSqliteDb(JSObject _) {
  external JSFunction get prepare;
  external JSFunction get exec;
  external JSFunction get close;
}

Files: mcp_server.dart (30+), database.dart (5), statement.dart (4), js_helpers.dart (10+), testing_library.dart (9), extension_context.dart (3), stdio_transport.dart (4), server.dart (2)


Pattern 2: dartify() result casts (15+ occurrences)

Current:

final map = dartified as Map<Object?, Object?>;
final state = jsState.dartify() as TState;

Replace with: Pattern matching with proper error handling

final map = switch (dartified) {
  final Map<Object?, Object?> m => m,
  _ => throw StateError('Expected Map, got ${dartified.runtimeType}'),
};

Or better: return Result<T, E> per project conventions.

Files: statement.dart (1), mcp_server.dart (2), reducer_hook.dart (6), ref.dart (1)


Pattern 3: Memoization cache unwrapping (16 occurrences)

Current:

R? lastResult;
// ...later...
return lastResult as R;  // nullable → non-nullable

Replace with: Proper null handling with a sentinel or flag

bool hasResult = false;
R? lastResult;
// ...
if (hasResult) return lastResult as R; // or use a wrapper type

Files: selectors.dart (16 occurrences — all identical pattern)


Pattern 4: null as T (4 occurrences)

Current:

return null as T;

Replace with: Proper nullable generic bounds

T? useState<T>(...) // make return type nullable
// or
T useState<T extends Object>(...) // constrain T to non-nullable

Files: state_hook.dart (3), state_hook.dart (1)


Pattern 5: Result type unwrapping (4+ occurrences)

Current:

final success = moduleResult as Success<JSObject, String>;

Replace with: Pattern matching (which nadz supports)

switch (moduleResult) {
  case Success(value: final module): // use module
  case Failure(error: final err): // handle error
}

Files: npm_component.dart (4), enhancers.dart (1)


Priority Order

  1. mcp_server.dart (49 casts) — biggest offender, create extension types for the MCP SDK JS objects
  2. selectors.dart (16 casts) — all identical pattern, one fix applies to all
  3. js_helpers.dart (12 casts) — already a helpers file, perfect place to add type-safe accessors
  4. testing.dart (11 casts) — React Native test utilities
  5. statement.dart + database.dart (17 combined) — SQLite bindings, create extension types
  6. Everything else

Acceptance Criteria

  • Zero as casts in any packages/*/lib/ file
  • All replacements use pattern matching, extension types, or safe conversion helpers
  • All existing tests still pass
  • No new dynamic introduced as a side effect

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions