2

For reference, I am using React 16.9.0 and Typescript 3.5.3. If you install Create React App and create a Typescript project, you can add the following minimal example to reproduce the problem:

import React from 'react';
import './App.css';

interface TreeComponentProps {
  recursion_level: number;
}

interface TreeComponentState {
}

class TreeComponent extends React.Component<TreeComponentProps, TreeComponentState>
{
  constructor(props: TreeComponentProps) {
    super(props);
    this.state = {
    };
  }

  render() {
    console.log( 'I was triggered during TreeComponent render...' );

    // const ListElements: any = (props: any) =>
    const ListElements: React.FunctionComponent<TreeComponentProps> = (props: TreeComponentProps) =>
    {
      if( props.recursion_level > 1 )
      {
        return (
          <ol>
            {props.children}
          </ol>
        );
      }
      else {
        return (
          <React.Fragment>
            {props.children}
          </React.Fragment>
        );
      }
    }

    if( this.props.recursion_level > 3 ) {
      return <div> End recursion on {this.props.recursion_level}... </div>
    }

    return (
      <ListElements>
        <div> recursion_level {this.props.recursion_level + 1} <br /> </div>
        <TreeComponent key={0} recursion_level={ this.props.recursion_level + 1 }/>
      </ListElements>
    )
  }
}

interface AppProps {
}

interface AppState {
}

class App extends React.Component<AppProps, AppState>
{
  private recursion_level: number;

  constructor(props: AppProps) {
    super(props);

    this.recursion_level = 0;
    this.state = {
    };
  }

  render() {
    console.log( 'I was triggered during App render:', this.state )

    return (
        <TreeComponent key={0} recursion_level={ this.recursion_level }/>
    )
  }
}

export default App;

-->

Property 'children' does not exist on type 'TreeComponentProps'.  TS2339

    27 |         return (
    28 |           <ol>
  > 29 |             {props.children}
       |                    ^
    30 |           </ol>
    31 |         );
    32 |       }

If I replace the line:

const ListElements: React.FunctionComponent<TreeComponentProps> = (props: TreeComponentProps) =>
// -->
const ListElements: any = (props: any) =>

Then, everything works fine and the page is generated correctly:

recursion_level 1
recursion_level 2
recursion_level 3
recursion_level 4
End recursion on 4...

I already researched and accordingly to this question How to use children with React Stateless Functional Component in TypeScript? this is the correct syntax:

Since React 16.8, the names React.SFC and React.StatelessComponent are depricated. Actually, they have become aliases for React.FunctionComponent type or React.FC for short.

You would use them the same way though:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

How can I correctly set my internal function props type for typescript without having to keep using any everywhere?

Evandro Coan
  • 8,560
  • 11
  • 83
  • 144

1 Answers1

3

You don't need to explicitly declare the type of MyStatelessComponent as it can be inferred.

Also since you don't use children in your second TreeComponent declaration so you need to mark children optional to remove type errors.

You're also missing the prop recursion_level={this.props.recursion_level} to your ListElements component

import React from 'react';
import './App.css';

interface TreeComponentProps {
  recursion_level: number;
  children?:React.ReactNode
}

interface TreeComponentState {
}

class TreeComponent extends React.Component<TreeComponentProps, TreeComponentState>
{
  constructor(props: TreeComponentProps) {
    super(props);
    this.state = {
    };
  }

  render() {
    console.log( 'I was triggered during TreeComponent render...' );

    // const ListElements: any = (props: any) =>
    const ListElements = (props: TreeComponentProps) =>
    {
      if( props.recursion_level > 1 )
      {
        return (
          <ol>
            {props.children}
          </ol>
        );
      }
      else {
        return (
          <React.Fragment>
            {props.children}
          </React.Fragment>
        );
      }
    }

    if( this.props.recursion_level > 3 ) {
      return <div> End recursion on {this.props.recursion_level}... </div>
    }

    return (
      <ListElements recursion_level={this.props.recursion_level}>
        <div> recursion_level {this.props.recursion_level + 1} <br /> </div>
        <TreeComponent key={0} recursion_level={ this.props.recursion_level + 1 }/>
      </ListElements>
    )
  }
}

interface AppProps {
}

interface AppState {
}

class App extends React.Component<AppProps, AppState>
{
  private recursion_level: number;

  constructor(props: AppProps) {
    super(props);

    this.recursion_level = 0;
    this.state = {
    };
  }

  render() {
    console.log( 'I was triggered during App render:', this.state )

    return (
        <TreeComponent key={0} recursion_level={ this.recursion_level }/>
    )
  }
}

export default App;
Damian Green
  • 6,895
  • 2
  • 31
  • 43