javascript - Hur man sätter typ för funktionsegenskaper för dess barn i Typescript? Egenskapen 'children' finns inte på typen TS2339


Som referens använder jag React 16.9.0 och Typescript 3.5.3. Om du installerar Create React App och skapar ett Typescript-projekt kan du lägga till följande minimala exempel för att återskapa problemet:

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 |       }

Om jag ersätter raden:

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

Då fungerar allt fint och sidan genereras korrekt:

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

Jag har redan forskat och enligt denna fråga Hur använder man children med React Stateless Functional Component i TypeScript? är detta den korrekta syntaxen:

Sedan React 16.8 är namnen React.SFC och React.StatelessComponent föråldrade. Faktiskt har de blivit alias för typen React.FunctionComponent eller React.FC för kort.

Du skulle använda dem på samma sätt ändå:

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

Hur kan jag korrekt ställa in typen för mina interna funktionsprops i TypeScript utan att behöva använda any överallt?

Svar #1

Du behöver inte uttryckligen deklarera typen av MyStatelessComponent eftersom den kan härledas.

Eftersom du inte använder children i din andra TreeComponent-deklaration måste du markera children som valfri för att ta bort typefel.

Du saknar också prop recursion_level={this.props.recursion_level} till din ListElements-komponent

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;