Mastersam07 / Mastersam07/kaisel

feat: let a route declare its result type so pop() and pushForResult<T>() are checked against each other

Open
#61 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement pkg:kaisel_core
Dominant language
Dart
Stars
69
Forks
2
Avg merge
18m
Merged PRs (30d)
9

Description

There is currently no type relationship between what a route pops and what its caller awaits.

`pushForResult(route)` declares what the **caller** expects. `pop([Object? result])` declares nothing about what the **route** produces. Neither is checked against the other:

```dart
// compiles cleanly; returns null (or throws) at runtime
router.pop(a string);
final wallet = await router.pushForResult(SelectWalletRoute());
```

auto_route had `pop(result)`, which at least typed the producing side. Migrating that to kaisel means **dropping** the only annotation that existed.

## Why migrations make this worse, not better

Routes that carry callbacks (`onComplete`, `onClose`, `onAction`) cannot survive as kaisel routes — routes are const value types with `props`, and a closure field breaks both const-ness and equality. The natural fix is to convert the callback into a popped result. That is the right move, but it means the number of result-carrying routes goes **up** during migration, on exactly the axis that has no type safety.

In one app this converted 13 routes from callback-carrying to result-returning. Every one of those is now an untyped contract between two files.

## `run` is not a general answer

`KaiselModalRoute` + `run` gives a real typed completion contract, but only for modal flows. A plain screen that returns a value — a picker, a filter sheet promoted to a full screen, a confirmation step — has no equivalent.

## Suggestion

Let a route declare its own result type:

```dart
abstract class KaiselResultRoute extends KaiselRoute {
const KaiselResultRoute();
}

final class SelectWallet extends AppRoute implements KaiselResultRoute {
const SelectWallet();
}
```

Then:

* `pushForResult` infers `T` from the route (`router.pushForResult(SelectWallet())` → `Future`),
* `pop` can be checked against the top routes declared type.

Failing that, a `pop(T result)` overload would at least restore parity with auto_route by typing the producing side.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading KaiselRoute, pushForResult, pop, and KaiselModalRoute/run, since the issue compares their current result contracts. Trace how a plain route and its caller communicate a result, then evaluate the proposed route-declared type against the typed pop fallback. Done means a non-modal route's produced result and the caller's awaited result are checked consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter
Domain
mobile-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.