toss / use-funnel

A powerful and safe step-by-step state management library
https://use-funnel.slash.page
MIT License
192 stars 25 forks source link

[Bug]: If the result of createFunnelSteps is passed to steps in @use-funnel/react-router-dom, type inference does not work. #52

Closed XionWCFM closed 2 months ago

XionWCFM commented 2 months ago

Package Scope

@use-funnel/react-router-dom

Bug description

When trying to define the structure of a funnel using createFunnelSteps, the type of the result of useFunnel is not properly inferred and is inferred as any or never.

I think this is a bug. Because in the case of @use-funnel/browser, the type can be properly defined using createFunenlSteps, as expected.

Expected behavior

We also want the funnel defined through createFunnelSteps to have its type inferred appropriately

To Reproduce

I wondered if this phenomenon only occurred in certain TS versions, so I reproduced it in 5.5 version and 5.7 version.

At least the version I reproduced showed the same problem.

import { createFunnelSteps, useFunnel } from "@use-funnel/react-router-dom";

type RemittanceFunnelType = {
  example?: string;
};

const exampleSteps = createFunnelSteps<RemittanceFunnelType>()
  .extends("start")
  .extends("end", { requiredKeys: "example" })
  .build();

const Hi = () => {
  // Here, the type of the funnel variable is inferred as follows.
  //  UseFunnelResults<Record<string, AnyContext>, ReactRouterDomRouteOption>
  const funnel = useFunnel({
    id: "example",
    steps: exampleSteps,
    initial: { context: {}, step: "start" },
  });

  return (
    <div>
      <funnel.Render
        start={({ context, history }) => {
          // We set the end step to require an example, but it doesn't work.
          history.push("end", {}); 
        }}
      />
    </div>
  );
};

Possible Solution

I don't have a deep understanding of the code of the @use-funnel library.

However, after realizing the problem, I was able to quickly look at the code and realize that the packages causing the problem had something in common.

This is part of the implementation code of @use-funnel/react-router-dom.

export const useFunnel = createUseFunnel<ReactRouterDomRouteOption>(({ id, initialState }) => {

And this is an example of @use-funnel/browser with createFunnelSteps working properly:

export const useFunnel = createUseFunnel(({ id, initialState }) => {

As I was exploring this issue, I realized that this wasn't just @use-funnel/react-router-dom's problem.

This issue also appears in @use-funnel/next.

And if you look at the implementation of @use-funnel/next, it is as follows.

export const useFunnel = createUseFunnel<NextPageRouteOption>(({ id, initialState }) => {

So, I think it would be a good idea to check the generic type of createUseFunnel.

etc.

Thank you for creating a great library and releasing it to the world.

I got a lot of inspiration from looking at this library.

thank you! 🥰

minuukang commented 2 months ago

Thanks for your interest and for reporting the issue! It was a bug in the PR (https://github.com/toss/use-funnel/pull/49) fix that was bumped up to version 0.0.4.

It is not issue of the generic of createUseFunnel. when expanding steps in createFunnelSteps() without using requiredKeys and expanding from the current state, the never type was initially given as context, so the start you reported was not properly typed.

This will be fixed soon and the version will be updated (0.0.5).

XionWCFM commented 2 months ago

Thanks for your interest and for reporting the issue! It was a bug in the PR (#49) fix that was bumped up to version 0.0.4.

It is not issue of the generic of createUseFunnel. when expanding steps in createFunnelSteps() without using requiredKeys and expanding from the current state, the never type was initially given as context, so the start you reported was not properly typed.

This will be fixed soon and the version will be updated (0.0.5).

okay! I'm looking forward to version 0.0.5. Thank you for your work.