Search code examples
reactjstypescriptreact-functional-componentreact-forwardref

How to bind components to component after using forwardRef?


I need bind Title and Body components to Wrapper component.

Before, I wrote my component like this:

import { FC } from 'react';

// need bound components
const Title: FC<...> = () => {...}
const Body: FC<...> = () => {...}

interface WrapperProps{...}
interface WrapperInterface extends FC<WrapperProps>{
  Title: typeof Title // bind Title component
  Body: typeof Body // bind Body Component
}
const Wrapper: WrapperInterface = () => {...}

Wrapper.Title = Title;
Wrapper.Body = Body;

After using forwardRef, I modified WrapperInterface, But typescript always prompts me that I am missing Title and Body properties, this is the WrapperInterface code:

import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react'

// need bound components
const Title: FC<...> = () => {...}
const Body: FC<...> = () => {...}

interface WrapperRef{...}
interface WrapperProps{...}
interface WrapperInstance extends ForwardRefExoticComponent<WrapperProps & RefAttributes<WrapperRef>>{
  Title: typeof Title // bind Title component
  Body: typeof Body // bind Body Component
}

const Wrapper: WrapperInstance = forwardRef((props, ref) => {...});
// TS2739: Type 'ForwardRefExoticComponent  >' is missing the following properties from type 'WrapperInterface': Title, Body
Wrapper.Title = Title;
Wrapper.Body = Body;

Not directly exported because the Body and Title components are too common.

How can I solve this problem?


Solution

  • Based on this github issue and the solution reported in it, you can solve the above problem by typecasting the component as WrapperInstance like

    import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react'
    
    // need bound components
    const Title: FC<...> = () => {...}
    const Body: FC<...> = () => {...}
    
    interface WrapperRef{...}
    interface WrapperProps{...}
    interface WrapperInstance extends ForwardRefExoticComponent<WrapperProps & RefAttributes<WrapperRef>>{
      Title: typeof Title // bind Title component
      Body: typeof Body // bind Body Component
    }
    
    const Wrapper = forwardRef<WrapperRef, WrapperProps>((props, ref) => {...}) as WrapperInstance;
    Wrapper.Title = Title;
    Wrapper.Body = Body;