Property 'token' is missing in type 'PropsWithChildren<WithUrqlProps>' but required in type '{ token: string; }'

Viewed 1006

I get this error at (ChangePassword) in export default withUrqlClient(createUrqlClient)(ChangePassword):

Argument of type 'FunctionComponent<{ token: string; }> & { getInitialProps?(context: NextPageContext): { token: string; } | Promise<{ token: string; }>; }' is not assignable to parameter of type 'NextComponentType<PartialNextContext, {}, {}>'. Type 'FunctionComponent<{ token: string; }> & { getInitialProps?(context: NextPageContext): { token: string; } | Promise<{ token: string; }>; }' is not assignable to type 'FunctionComponent & { getInitialProps?(context: PartialNextContext): {} | Promise<{}>; }'. Type 'FunctionComponent<{ token: string; }> & { getInitialProps?(context: NextPageContext): { token: string; } | Promise<{ token: string; }>; }' is not assignable to type 'FunctionComponent'. Types of parameters 'props' and 'props' are incompatible. Type 'PropsWithChildren' is not assignable to type 'PropsWithChildren<{ token: string; }>'. Property 'token' is missing in type 'PropsWithChildren' but required in type '{ token: string; }'.ts(2345)

Here is the code:

import { NextPage } from "next";
import { Wrapper } from "../../components/Wrapper";
import { Formik, Form } from "formik";
import { toErrorMap } from "../../utils/toErrorMap";
import { InputField } from "../../components/InputField";
import { Box, Button, Link, Flex } from "@chakra-ui/react";
import { useChangePasswordMutation } from "../../generated/graphql";
import { useRouter } from "next/router";
import { withUrqlClient } from "next-urql";
import { createUrqlClient } from "../../utils/createUrqlClient";
import NextLink from "next/link";

const ChangePassword: NextPage<{ token: string }> = ({ token }) => {
  const router = useRouter();
  const [, changePassword] = useChangePasswordMutation();
  const [tokenError, setTokenError] = useState("");
  return (
    <Wrapper variant="small">
      <Formik
        initialValues={{ newPassword: "" }}
        onSubmit={async (values, { setErrors }) => {
          const response = await changePassword({
            newPassword: values.newPassword,
            token,
          });
          if (response.data?.changePassword.errors) {
            const errorMap = toErrorMap(response.data.changePassword.errors);
            if ("token" in errorMap) {
              setTokenError(errorMap.token);
            }
            setErrors(errorMap);
          } else if (response.data?.changePassword.user) {
            // worked
            router.push("/");
          }
        }}
      >
        {({ isSubmitting }) => (
          <Form>
            <InputField
              name="newPassword"
              placeholder="new password"
              label="New Password"
              type="password"
            />
            {tokenError ? (
              <Flex>
                <Box mr={2} style={{ color: "red" }}>
                  {tokenError}
                </Box>
                <NextLink href="/forgot-password">
                  <Link>click here to get a new password</Link>
                </NextLink>
              </Flex>
            ) : null}
            <Button
              mt={4}
              type="submit"
              isLoading={isSubmitting}
              variantColor="teal"
            >
              change password
            </Button>
          </Form>
        )}
      </Formik>
    </Wrapper>
  );
};

ChangePassword.getInitialProps = ({ query }) => {
  return {
    token: query.token as string,
  };
};

export default withUrqlClient(createUrqlClient)(ChangePassword);
3 Answers

I have a quick have which will solve your type problem

export default withUrqlClient(createUrqlClient)(ChangePassword as any);

by type casting the changePassword to any it get the type at compile and it not show any warming

(note: there will no auto complete or type if you follow this)

I could type mine in a different way and I hope it is the right way to do so. My approach was:

export default withUrqlClient(createUrlClient)(
  ChangePassword as FunctionComponent<
    PropsWithChildren<WithUrqlProps | { token: string }>
  >
);

Where the types:

  • FunctionComponent, PropsWithChildren were imported from "react"
  • WithUrqlProps was imported from "next-urql"

You can get the query token from useRouter instead of getInitialProps.

import { Box, Button, Flex, Link } from "@chakra-ui/react";
import { Form, Formik } from "formik";
import { withUrqlClient } from "next-urql";
import { useRouter } from "next/router";
import React, { useState } from "react";
import InputField from "../../components/InputField";
import Wrapper from "../../components/Wrapper";
import { useChangePasswordMutation } from "../../generated/graphql";
import { createUrqlClient } from "../../utils/createUrqlClient";
import { toErrorMap } from "../../utils/toErrorMap";
import NextLink from "next/link";

const ChangePassword = () => {
  const [, changePassword] = useChangePasswordMutation();
  const [tokenError, setTokenError] = useState("");

  const router = useRouter();
  const { token } = router.query;

  return (
    <Wrapper variant="small">
      <Formik
        initialValues={{ newPassword: "" }}
        onSubmit={async (values, { setErrors }) => {
          const response = await changePassword({
            newPassword: values.newPassword,
            token: token as string,
          });
          if (response.data?.changePassword.errors) {
            const errorMap = toErrorMap(response.data.changePassword.errors);
            if ("token" in errorMap) {
              setTokenError(errorMap.token);
            }
            setErrors(errorMap);
          } else if (response.data?.changePassword.user) {
            router.push("/");
          }
        }}
      >
        {({ isSubmitting }) => (
          <Form>
            <InputField
              name="newPassword"
              placeholder="new password"
              label="New Password"
              type="password"
            />
            {tokenError ? (
              <Flex>
                <Box mr={2} color="red">
                  {tokenError}
                </Box>
                <NextLink href="/forgot-password">
                  <Link>click here to get a new one</Link>
                </NextLink>
              </Flex>
            ) : null}
            <Box mt={4}>
              <Button type="submit" isLoading={isSubmitting} colorScheme="teal">
                change password
              </Button>
            </Box>
          </Form>
        )}
      </Formik>
    </Wrapper>
  );
};

export default withUrqlClient(createUrqlClient)(ChangePassword);

Related