0
votes

I am wondering how to pass JSX (like "div" or "span") or React components to my own component. So, I tried to work with React.ReactType to support both. My Code looks like the following:

LazySvgIcon.tsx

import * as React from 'react'

interface Props {
  src: string
  loading?: React.ReactType
  error?: React.ReactType
}

interface State {
  isLoading: boolean,
  hasError: boolean
}

export const LazySvgIcon = 
  class LazySvgIcon extends React.Component<Props, State> {
    constructor(props: Props, context?: any) {
      super(props, context)

      this.state = {
        isLoading: false,
        hasError: false
      }
    }

    render() {
      const { isLoading, hasError } = this.state
      const { loading:Loader, error:Error } = this.props
      return(
        <React.Fragment>
          { isLoading && Loader && <Loader /> }
          { hasError && Error && <Error /> }
        </React.Fragment>
      )
    }
  }

However I get the error for my Loader and Error component that...

[ts] JSX element type 'Loader' does not have any construct or call signatures. [2604]

When I change ReactType to ComponentType, the code is working, but this is not what I want, because then I can't pass a <div> container for instance.

What's the correct way to use React.ReactType with TypeScript in *.tsx files?

Versions in use: TypeScript 3.2.4, React 16.7.0

1

1 Answers

0
votes

React.ReactType describes the types of class and functional components. For elements you can use React.ReactNode instead. For your example it is not clear if you want to pass a component (also called render prop) or an element as a prop.

If you want to pass an element change your Props to:

interface Props {
    src: string
    loading?: React.ReactNode
    error?: React.ReactNode
}

And remove the type annotations when you destructure your props in render:

const { loading, error: } = this.props

If you want to pass a component as a prop, you should capitalize it if you want to use it after destructuring, as JSX interprets lowercased components as html elements. interface Props { src: string LoadingComponent?: React.ReactType ErrorComponent?: React.ReactType } and in your render:

return(
    <React.Fragment>
      { isLoading && <LoadingComponent /> && <Loader /> }
      { hasError && <ErrorComponent/> && <Error /> }
    </React.Fragment>
  )