Typescript - A function which returns a function with generic type - what does it do?

Viewed 97

I am new to TypeScript and came across a piece of code which confused me to no end. I am trying to understand what the function componentControl does below but I don't think I fully grasp it.

componentControl:

const componentControl: <P extends object>(
  options: BaseProps<P>
) => React.FunctionComponent<P> = <P extends object>(options: BaseProps<P>) => {
  const defaultBaseProps = {
    onInit: () => Promise.resolve(),
    onLoading: () => Promise.resolve(),
    onLoaded: () => Promise.resolve(),
    onSubmit: () => Promise.resolve(),
    onSubmitSuccess: () => Promise.resolve(),
    onDestroy: undefined,
    onError: () => Promise.resolve(),
    onLoadingFailure: () => Promise.resolve(),
    onSubmitFailure: () => Promise.resolve(),
    InitComponent: () => <PageSpinner />,
    LoadingComponent: () => <PageSpinner />,
    LoadedComponent: () => <h1>The component has been loaded.</h1>,
    SubmittingComponent: () => <PageSpinner />,
    SubmitSuccessComponent: () => <h1>Submitted successfully.</h1>,
    ErrorComponent: DefaultErrorComponent,
    LoadingFailureComponent: DefaultErrorComponent,
    SubmitFailureComponent: DefaultErrorComponent,
  };
  return (wrapped: P) => {
    const props: BaseComponentProps<P> = {
      base: { ...defaultBaseProps, ...options },
      wrapped: wrapped
    };
    return <BaseComponent {...props} />;
  };
};

BaseProps:

export interface BaseProps<P> {
  onInit?: (props: P & BaseContextType) => Promise<void>;
  onLoading?: (props: P & BaseContextType) => Promise<void>;
  onLoaded?: (props: P & BaseContextType) => Promise<void>;
  onSubmit?: (
    props: P & BaseContextType & { submittedData: unknown }
  ) => Promise<void>;
  onSubmitSuccess?: (props: P & BaseContextType) => Promise<void>;
  onDestroy?: (props: P & BaseContextType) => Promise<void>;
  onError?: (
    props: { err: Error | string | unknown } & BaseContextType
  ) => Promise<void>;
  onLoadingFailure?: (
    props: { err: Error | string | unknown } & BaseContextType
  ) => Promise<void>;
  onSubmitFailure?: (
    props: { err: Error | string | unknown } & BaseContextType
  ) => Promise<void>;

  InitComponent?: React.FunctionComponent<P>;
  LoadingComponent?: React.FunctionComponent<P>;
  LoadedComponent?: React.FunctionComponent<P>;
  SubmittingComponent?: React.FunctionComponent<P>;
  SubmitSuccessComponent?: React.FunctionComponent<P>;
  ErrorComponent?: React.FunctionComponent<
    P & { err: Error | string | unknown }
  >;
  LoadingFailureComponent?: React.FunctionComponent<
    P & { err: Error | string | unknown }
  >;
  SubmitFailureComponent?: React.FunctionComponent<
    P & { err: Error | string | unknown }
  >;
}

BaseComponentProps:

export interface BaseComponentProps<P> {
  base: BaseProps<P>;
  wrapped: P;
}

If I hover over the function name componentControl in IntelliJ, it shows this: export default function componentControl<P>(options: BaseProps<P>): (wrapped: P) => JSX.Element. What exactly is the input of the this function? Is it the options of type BaseProps or wrapped of type P? What is the use of wrapped? And does this function returns this function below?

(wrapped: P) => {
    const props: BaseComponentProps<P> = {
      base: { ...defaultBaseProps, ...options },
      wrapped: wrapped
    };
    return <BaseComponent {...props} />;
  };

Finally, how am I supposed to use/call this function? Thank you so much for reading.

1 Answers

let's go step by step:

  1. What exactly is the input of this function?: The input/arguments of this function (componentControl) it's an options object (which should follow the constraints specified in the BaseProps interface. Bear in mind you will also need to send the value for the generic type P in my example is the {someProp: boolean} interface. This will tell your component that the value of P is that interface so if u try to send as props an onInit function that does not have {someProp: boolean} as the argument type it will return an error. This constrain is defined in the BaseProps interface here onInit?: (props: P & BaseContextType) => Promise<void>; where P === {someProp: boolean} in my example.

  2. Is it the options of type BaseProps or wrapped of type P? : As I said the argument of that function is the options object.

  3. What is the use of wrapped? : The function componentControl returns a functional component (as you can see its typed in line 3 ) => React.FunctionComponent<P>. So if you do:

const NewControledComponent = componentControl<{someProp: boolean}>({onInit}) // P === {someProp}

<NewControledComponent someProp={false} /> // wrapped === props === {someProp: false}

wrapped is only the name used to reference the component props (calling them props or wrappedComponentProps would be more accurate.

  1. And does this function returns this function below?: Yes, it return the function below which it means to be a React Functional Component

  2. how am I supposed to use/call this function?: Like a normal function, but you need to bear in mind that it will return a React functional Component.

Related