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

RFC: Cannot pass react.VFC typed component to withAuthUser argument #142

Closed
Tracked by #265
Qs-F opened this issue Apr 15, 2021 · 8 comments
Closed
Tracked by #265

RFC: Cannot pass react.VFC typed component to withAuthUser argument #142

Qs-F opened this issue Apr 15, 2021 · 8 comments
Labels
help wanted Extra attention is needed RFC Request for comments and ideas

Comments

@Qs-F
Copy link

Qs-F commented Apr 15, 2021

Describe the bug

Since withAuthUser argument type is react.ComponentType (ref:

}) => (component: ComponentType<P>) => ComponentType<P>
), react.VFC cannot be passed.

However, IDK which is better, to fix next-firebase-auth type definition or DefinetelyTyped react type definition.
If you have any suggestions, please let me know.

Version

0.12.2

To Reproduce

Pass react.VFC typed component to withAuthUser argument.

Expected behavior

Does not produce type error.

Additional context

(About react.Component)
react.ComponentType definition:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L78
This lacks react.VoidFunctionalComponent
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L539-L555

(About react.VFC)
Currently, with react.FC typed component seems implicitly receiving children.
So React team recommends to use react.VFC (which we have to write children explicitly when we want), and from React v18 react.FC will be modified behaviorally equivalent to react.VFC.

@grahaml
Copy link
Contributor

grahaml commented Apr 15, 2021

I actually came here to open a similar issue. If you use Next.js' provided InferGetServerSideProps as the type for a page, then compilation fails with this error:

Type error: Argument of type 'FunctionComponent<never> & { getInitialProps?(context: NextPageContext<any>): Promise<never>; }' is not assignable to parameter of type 'ComponentType<{}>'.
  Type 'FunctionComponent<never> & { getInitialProps?(context: NextPageContext<any>): Promise<never>; }' is not assignable to type 'FunctionComponent<{}>'.
    Types of parameters 'props' and 'props' are incompatible.
      Type '{ children?: ReactNode; }' is not assignable to type 'never'.

Here is a basic example.

const MyBasicPage: NextPage<
	InferGetServerSidePropsType<typeof getServerSideProps>
> = ({ somethingFromServer }) => {
	return (
		<div>My Page!</div>
	);
};

export default withAuthUser({
	whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
	whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
	LoaderComponent: Loading,
})(MyBasicPage); // <--- This trips up the compiler

export const getServerSideProps = withAuthUserTokenSSR({
	whenAuthed: AuthAction.RENDER,
	whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
})(async () => {
	const res = await fetch('https://..../api/something');
	const somethingFromServer = await res.json();
	return { props: { somethingFromServer } };
});

I will note that it does work if I type the page as just NextPage. The issue is with InferGetServerSideProps from Next.js.

It's a hard call to make - whether React types or next-firebase-auth types need updating. I am leaning towards thinking that it would make sense for this library to have broader support with this function, especially given that there seems to be two common types that do not work here. However... FULL DISCLOSURE: I am not a TS expert! This is my first TS project, so my viewpoint may be a little skewed.

@kmjennison kmjennison added help wanted Extra attention is needed RFC Request for comments and ideas labels Apr 16, 2021
@kmjennison
Copy link
Contributor

Thanks for this issue! I welcome suggestions from people who have more experience with TS than I do. At a glance, it seems like switching to React.VFC makes sense if that's where React is headed, and it would be a minor breaking change here.

@timfee
Copy link

timfee commented Apr 24, 2021

I was going to request thing same thing after reading https://fettblog.eu/typescript-react-why-i-dont-use-react-fc/, as my pages return JSX.Element (which also don't have children).

Looking at other GitHub repos, JSX.Element | React.ComponentType seems like a pretty common type, but not sure if that works for React.VFC (and if it should be piped in)

@kmjennison
Copy link
Contributor

I converted one of the example pages to TypeScript and ran into a similar issue when using a normal function for the functional component:
https://github.com/gladly-team/next-firebase-auth/blob/main/example/pages/ssr-no-token.tsx#L86

@uncvrd
Copy link
Contributor

uncvrd commented Jul 8, 2021

I'm also stuck on how to use GetServerSideProps and InferGetServerSideProps to properly receive props in to my functional component when using an auth HOC. Has anyone been able to achieve this yet?

I personally see the following error when trying to type my getServerSideProps function with GetServerSideProps:

Type 'Promise<GetServerSidePropsResult<{ [key: string]: any; }>>' is not assignable to type 'GetServerSideProps<Props, ParsedUrlQuery>'.
  Type 'Promise<GetServerSidePropsResult<{ [key: string]: any; }>>' provides no match for the signature '(context: GetServerSidePropsContext<ParsedUrlQuery>): Promise<GetServerSidePropsResult<Props>>'

@kmjennison kmjennison changed the title Cannot pass react.VFC typed component to withAuthUser argument RFC: Cannot pass react.VFC typed component to withAuthUser argument Aug 3, 2021
@kmjennison kmjennison pinned this issue Aug 3, 2021
@kmjennison kmjennison mentioned this issue Aug 7, 2021
24 tasks
@gavinharris-dev
Copy link
Contributor

gavinharris-dev commented Aug 22, 2021

somethingFromServer
Hi @grahaml, I played around with your example and this seems to work okay:

import { Loading } from 'components/Loading/Loading';
import { InferGetServerSidePropsType, NextPage } from 'next';
import {
  AuthAction,
  withAuthUser,
  withAuthUserTokenSSR,
} from 'next-firebase-auth';


type InferType = InferGetServerSidePropsType<typeof myGetServerSideProps>;

const MyBasicPage: NextPage<InferType> = ({ somethingFromServer }) => {
  return <div>My Page! {somethingFromServer} </div>;
};

export default withAuthUser<InferType>({
  whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
  LoaderComponent: Loading,
})(MyBasicPage); // <--- This now works as we are telling withAuthUser what type to expect

const myGetServerSideProps = async () => {
  const res = await fetch('https://.../data');
  const somethingFromServer = await res.json();

  return {
    props: {
      somethingFromServer,
    },
  };
};

export const getServerSideProps = withAuthUserTokenSSR({
  whenAuthed: AuthAction.RENDER,
  whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
})(myGetServerSideProps);

It is a little messy having to declare the myGetServerSideProps method, but you can then Infer from that method and it appears to give the correct type... Does this make sense?

@gavinharris-dev
Copy link
Contributor

Interestingly enough this also works with VFC components:

import { Loading } from 'components/Loading/Loading';
import { InferGetServerSidePropsType } from 'next';
import {
  AuthAction,
  withAuthUser,
  withAuthUserTokenSSR,
} from 'next-firebase-auth';
import {VFC} from 'react';


type InferType = InferGetServerSidePropsType<typeof myGetServerSideProps>;

const MyBasicPage: VFC<InferType> = ({ somethingFromServer }) => {
  return <div>My Page! {somethingFromServer} </div>;
};

export default withAuthUser<InferType>({
  whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
  LoaderComponent: Loading,
})(MyBasicPage); // <--- This now works as we are telling withAuthUser what type to expect

const myGetServerSideProps = async () => {
  const res = await fetch('https://.../data');
  const somethingFromServer = await res.json();

  return {
    props: {
      somethingFromServer,
    },
  };
};

export const getServerSideProps = withAuthUserTokenSSR({
  whenAuthed: AuthAction.RENDER,
  whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
})(myGetServerSideProps);

gavinharris-dev pushed a commit to gavinharris-dev/next-firebase-auth that referenced this issue Aug 24, 2021
Added some details on the use of TypeScript with `withAuthUser` method.
kmjennison added a commit that referenced this issue Aug 27, 2021
#142: TypeScript and `withAuthUser`
@kmjennison
Copy link
Contributor

I believe this is closed by #283. See docs and example. Let me know if this approach causes any problems.

@kmjennison kmjennison unpinned this issue Aug 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed RFC Request for comments and ideas
Projects
None yet
Development

No branches or pull requests

6 participants