Search code examples
reactjstypescriptreact-functional-component

Passing Props from a Functional component to a class component


I am doing a React tutorial and author has a playground where everything works. But in my IDE when I try to pass props to a class component, the component does not recognize the props. I have been at it for a couple of hours now. Can someone point out what is wrong with my code and why it should be working at https://jscomplete.com/playground/rgs2.4

const testData = [
  {name: "Dan Abramov", avatar_url: "https://avatars0.githubusercontent.com/u/810438?v=4", company: "@facebook"},
  {name: "Sophie Alpert", avatar_url: "https://avatars2.githubusercontent.com/u/6820?v=4", company: "Humu"},
  {name: "Sebastian Markbåge", avatar_url: "https://avatars2.githubusercontent.com/u/63648?v=4", company: "Facebook"},
];

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);


class App extends React.Component {
  render() {
    return (
      <div>
        <div className="header">{this.props.title}</div>
        <CardList />
      </div>
    );
  }
}

root.render(
  <App title="The GitHub Cards App" />
);


const CardList = () => (
      <div>
        {testData.map(profile => <Card {...profile}/>)}
      </div>
);


class Card extends React.Component {
  render() {
      const profile = this.props;
      return (
          <div className="github-profile">
             <img src={profile.avatar_url} alt="Cant show "/>
             <div className="info" style={{verticalAlign:'top'}}>
              <div className="name" style={{fontSize:'125%'}}>{profile.name}</div>
              <div className="company">{profile.company}</div>
             </div>
          </div>
      );
  }
}

For example in the line < App title="The GitHub Cards App" / > I get following error on "title" in the render, and the App component says prop.title does not exist

No overload matches this call.
  Overload 1 of 2, '(props: {} | Readonly<{}>): App', gave the following error.
    Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{}>'.
      Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{}>'.
  Overload 2 of 2, '(props: {}, context: any): App', gave the following error.
    Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{}>'.
      Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{}>'

Again in the Card component, profile properties, like avatar_url, name and company are not present, for example - Property 'name' does not exist on type 'Readonly<{}>

There are slight differences in my version and the one on https://jscomplete.com/playground/rgs2.4 This is due to React version, probably not causing this situation. If anyone has a clue looking at this, please help me get unstuck.

Thanks


Solution

  • In Typescript, components are typed using Generics. The Component declaration is

    Component<P = {}, S = {}, SS = any>
    

    P: Props, default type = {}

    S: State, default type = {}

    SS: SnapShot, default type = any

    In your case you are trying to type the props.

    type AppProps = {
      title: string;
    };
    class App extends React.Component<AppProps> {
    ...
    
    type CardProps = {
      avatar_url: string;
      name: string;
      company: string;
    };
    class Card extends React.Component<CardProps> {
    ...
    

    With function components you can use FC<P = {}>, which just has the generic type for props

    type AppProps = {
      title: string;
    };
    const App: React.FC<AppProps> = ({ title }) => {
    ...
    
    type CardProps = {
      avatar_url: string;
      name: string;
      company: string;
    };
    const Card: React.FC<CardProps> = ({ avatar_url, name, company }) => {
    ...
    

    If you don't want to use Typescript, since the code you provided doesn't actually use any, name your file with extension .jsx instead of .tsx.