Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v8 TS types don't allow passing a component prop named context #1957

Closed
markerikson opened this issue Sep 23, 2022 · 2 comments · Fixed by #1958
Closed

v8 TS types don't allow passing a component prop named context #1957

markerikson opened this issue Sep 23, 2022 · 2 comments · Fixed by #1958
Labels

Comments

@markerikson
Copy link
Contributor

markerikson commented Sep 23, 2022

Original discussion in #1187 starting at #1187 (comment) , posted by @strongui .

Pasting some relevant comment extracts:

we have a huge app, we haven't had time to update until recently.

const connector = connect(mapStateToProps, mapDispatchToProps);

const connectorCore = connect(null, mapDispatchToPropsCoreMethods);

const BaseComp = (props) => {
  return <div></div>
}

// This COMP will get all it's data from the redux store
export const FullComponent = connector(BaseComp);
// This COMP will demand data from the parent
export const NonDataComponent = connectorCore(BaseComp);

Basically this. Same component, but one gets data form redux, the other will get data from parent.

Sandbox: https://codesandbox.io/s/tender-mestorf-x272kj?file=/src/index.tsx

now you see the TS error:

Type '"LIST"' is not assignable to type '("LIST" | "CARD") & Context<ReactReduxContextValue<any, AnyAction>>'.ts(2322)

From me:

Hmm. Interesting. If I fix the use of connector(Button), and then swap back to React-Redux v7, the wrapped Button component says that context is just that enum, not a ReactReduxContext instance.

I wonder what about our types changed there? It most likely had something to do with the TS conversion process.

The internal logic for "what do we do with props.context internally once we see it" hasn't changed, and if I'm reading this right, it ought to actually pass that through properly if it's not a context instance:

      const ContextToUse: ReactReduxContextInstance = useMemo(() => {
        // Users may optionally pass in a custom context instance to use instead of our ReactReduxContext.
        // Memoize the check that determines which context instance we should use.
        return propsContext &&
          propsContext.Consumer &&
          // @ts-ignore
          isContextConsumer(<propsContext.Consumer />)
          ? propsContext
          : Context
      }, [propsContext, Context])

      // Retrieve the store and ancestor subscription via context, if available
      const contextValue = useContext(ContextToUse)

It's probably this part:

export interface ConnectProps {
  /** A custom Context instance that the component can use to access the store from an alternate Provider using that same Context instance */
  context?: ReactReduxContextInstance
  /** A Redux store instance to be used for subscriptions instead of the store from a Provider */
  store?: Store
}

interface InternalConnectProps extends ConnectProps {
  reactReduxForwardedRef?: React.ForwardedRef<unknown>
}

    function ConnectFunction<TOwnProps>(
      props: InternalConnectProps & TOwnProps
    )  {
       // omit
    }

Given that, I think this would run, but it won't compile, which is an issue.

@markerikson
Copy link
Contributor Author

I've looked at it a bit this evening, and it comes down to this part:

// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render. Also adds new prop requirements from TNeedsProps.
// Uses distributive omit to preserve discriminated unions part of original prop type
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
  C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>
>(
  component: C
) => ConnectedComponent<
  C,
  DistributiveOmit<
    GetLibraryManagedProps<C>,
    keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>
  > &
    TNeedsProps &
    ConnectProps
>

Unfortunately, this all seems to come into play very early in the types handling, and we don't actually know what the final component's props actually are.

I'm still messing with it, but I'm not sure how easy or even feasible it will be to extract the props from the actual component you pass in.

@markerikson
Copy link
Contributor Author

update: I mayyyyyyy have just fixed this? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant