0

New to using Typescript and getting the following error:

Property 'classes' is missing in type '{ title: string; text: string; industry: string; location: string; image: string; date: string; link: string; }' but required in type 'CaseStudyCardProps'

I'm using react-jss for component styles, and wondering if there's a clash happening with the styles object vs passing the classes prop itself.

App.tsx

import CaseStudyCard from './components/CaseStudyCard'
function App() {
  return (
    <div className="App">
      <CaseStudyCard 
        title="Preparing organizations for the future"
        text="This is the body of the card and should wrap continuously" 
        industry="Healthcare" 
        location="Nowheresville" 
        image="https://source.unsplash.com/user/erondu/600x400"  
        date="March 22nd 2021"
        link="https://www.google.com"
      />
    </div>
  );
}

export default App;

CaseStudyCard.tsx

const CardHeader = ({classes, image}) => {
     const style = { 
              backgroundImage: `url(${image})`,
          };
          return (
            <header style={style} className={classes.cardHeader}>
              <h4 className={classes.cardHeader}>News</h4>
            </header>
          )
      }

const Button = ({classes, link}) => (
     <a href={link} className={classes.buttonPrimary}>
              Find out more
     </a>   
)
      
const CardBody = ({classes, date, title, text, link}) => {
      return (
        <div className={classes.cardBody}>
          <p className={classes.date}>{date}</p>
          <h2>{title}</h2>
          <p className={classes.bodyContent}>{text}</p>
          <Button classes={classes} link={link}/>
        </div>
      )
}

interface CaseStudyCardProps {
       image: string,
       classes: object,
       title: string,
       date: string,
       location: string,
       industry: string,
       link: string,
       text: string
     } 
      export default function CaseStudyCard (props: CaseStudyCardProps) {
        const classes = useStyles()
        return (
            <div className={classes.card}>
              <CardHeader classes={props.classes} image={props.image}/>
              <CardBody 
                classes={props.classes} 
                title={props.title} 
                date={props.date}
                location={props.location}
                industry={props.industry}
                link={props.link}
                text={props.text}
              />
            </div>
          )
      }
1
  • 1
    Just remove classes from the interface? Commented Mar 24, 2021 at 13:40

1 Answer 1

1

It is because you don't have a classes field here:

  <CaseStudyCard 
    title="Preparing organizations for the future"
    text="This is the body of the card and should wrap continuously" 
    industry="Healthcare" 
    location="Nowheresville" 
    image="https://source.unsplash.com/user/erondu/600x400"  
    date="March 22nd 2021"
    link="https://www.google.com"
  />

When you create a Typescript interface and put fields, Typescript will throw an error if you don't include that field.

Option 1

Make classes field optional:

interface CaseStudyCardProps {
       image: string,
       classes?: object,
       title: string,
       date: string,
       location: string,
       industry: string,
       link: string,
       text: string
     } 

Option 2

Remove the classes field from the interface. (Be careful with this, as if some of your CaseStudyCard instances receives a classes field, then Typescript will won't recognize that and throw an error)

interface CaseStudyCardProps {
       image: string,
       title: string,
       date: string,
       location: string,
       industry: string,
       link: string,
       text: string
     } 

Option 3

Give classes field to the object. (If you are doing this make sure you add accurate conditionals not to potentially get Can not access x field of undefined errors )

 <CaseStudyCard 
    title="Preparing organizations for the future"
    text="This is the body of the card and should wrap continuously" 
    industry="Healthcare" 
    location="Nowheresville" 
    image="https://source.unsplash.com/user/erondu/600x400"  
    date="March 22nd 2021"
    link="https://www.google.com"
    classes={}
  />

Edit: When your classes object's existence is not 100%, you have to add conditionals accordingly. For instance, you are using classes inside the CardBody

const CardBody = ({classes, date, title, text, link}) => {
      return (
        <div className={classes.cardBody}>
          <p className={classes.date}>{date}</p>
          <h2>{title}</h2>
          <p className={classes.bodyContent}>{text}</p>
          <Button classes={classes} link={link}/>
        </div>
      )
}

However, you don't have the classes or your classes is empty. In this case, you have to add an if check to avoid problems:

const CardBody = ({classes, date, title, text, link}) => {
      return classes && Object.keys(classes).length > 0 ? (
        <div className={classes.cardBody}>
          <p className={classes.date}>{date}</p>
          <h2>{title}</h2>
          <p className={classes.bodyContent}>{text}</p>
          <Button classes={classes} link={link}/>
        </div>
      ) : null
}

Or, more logically, don't even render CardBody when your classes object is empty:

  {Object.keys(props.classes).length > 0 && <CardBody 
        classes={props.classes} 
        title={props.title} 
        date={props.date}
        location={props.location}
        industry={props.industry}
        link={props.link}
        text={props.text}
      />}

And likewise, in CardHeader you use classes to render a JSX element. Don't render CardHeader if your classes is going to be empty. Or make sure you have your classes object 100%.

Sign up to request clarification or add additional context in comments.

10 Comments

By either removing it or setting classes?: object, I get the error: Binding element 'classes' implicitly has an 'any' type. when importing classes as a prop in const CardHeader = ({classes, image}) => {...}
You have to decide based on your condition, if you destructure classes like that, you need to keep it in the interface and pass some dummy object when you don't need it. Like option 3.
By providing classes?: object and and empty classes prop classes={}, I get JSX attributes must only be assigned a non-empty expression
When you define an interface, you are saying typescript that, when you see a variable of this type, these are going to be the fields. Now, some fields can exist or not, in which case you do like classes?: object. If that is the case, before destructuring it you can add an if check if(props.hasOwnProperty("classes")) classes = props.classes. So, bascially you got to decide and structure your dependent code accordingly. Or you can add a check to see if classes is empty, before rendering it as a JSX element
Maybe it's the lack of coffee yet, but I've used the classes?: object logic, and trying to figure out where I'd use the check if the classes property exist, but still getting the error JSX attributes must only be assigned a non-empty expression
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.