2

I'm learning React with TypeScript, and am building a simple chore logger (where users enter chore information, which is then logged as a new document).

So, users enter their chore details, hits submit, and on submit a new choreDoc object is created that holds all their information. This object also contains a method format() that takes the user information and returns it as a string. I want to pass this entire object as a prop to the Document.tsx component, and then within this component extract the format() function, and render the returned data. I'm just confused about how to do this, and when I try to pass the choreDoc object as a prop, I get the following linting error:

Type '{ document: {}; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
  Property 'document' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; 

Any ideas of how to fix this?

Main parent component where user information is entered and extracted: App.tsx

import React, {useState} from 'react';
import Document from './Document'
import './styles.css'

interface Formatter {
  format(): string
}

class choreDoc implements Formatter  {
  name:string
  chore:string
  date:string

  constructor(n:string,c:string,d:string){
    this.name = n
    this.chore = c
    this.date = d
  }

  format(){
    return `${this.name} completed this following chore: ${this.chore} on the following date: ${this.date}`
  }
}

function App() {
  const [name, setName] = useState('')
  const [chore, setChore] = useState('')
  const [date, setDate] = useState('')
  const [document, setDocument] = useState({})

  const handleNameChange = (e:React.FormEvent<HTMLInputElement>) => {
      e.preventDefault()
      setName(e.currentTarget.value)
  }
  const handleChoreChange = (e:React.FormEvent<HTMLInputElement>) => {
      e.preventDefault()
      setChore(e.currentTarget.value)
  }
  const handleDateChange = (e:React.FormEvent<HTMLInputElement>)=> {
      e.preventDefault()
      setDate(e.currentTarget.value)
  }
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>)=> {
    e.preventDefault()
    let doc:Formatter = new choreDoc(name,chore,date)
    let arr = []
    arr.push(doc)
    setDocument(arr)
  }

  return(
    <>
      <div>
          <form className = 'input-list' onSubmit = {handleSubmit} >
              <label>
              Enter Name <br></br>
              <input type = 'text' name = 'name' onChange = {handleNameChange}></input>
              </label>
              <label>
              Chore <br></br>
              <input type = 'text' name = 'chore' onChange = {handleChoreChange}></input>
              </label>
              <label>
              Date completed <br></br>
              <input type = 'text' name = 'date' onChange = {handleDateChange}></input>
              </label>
              <div>
              <button type = 'submit' >Submit</button>
              </div>
          </form>
      </div>
      <div>
        <Document document = {document}/>
      </div>
      </>
  )
}

export default App;

Document.tsx where I want to render the returned information from format()

import React from 'react'

interface Props {
    format():string
}

const Document: React.FC<Props> = () => {
    return(
        <div className = 'doc'>
        </div>
    )
}

export default Document

1 Answer 1

1

By putting the document prop in the Props interface as a Formatter, and by putting the document directly in the state instead of in an array it will work as expected.

import React, { useState } from "react";

interface Props {
  document: Formatter;
}

const Document: React.FC<Props> = ({ document }) => {
  return <div className="doc">{document.format()}</div>;
};

interface Formatter {
  format(): string;
}

class ChoreDoc implements Formatter {
  name: string;
  chore: string;
  date: string;

  constructor(n: string, c: string, d: string) {
    this.name = n;
    this.chore = c;
    this.date = d;
  }

  format() {
    return `${this.name} completed this following chore: ${this.chore} on the following date: ${this.date}`;
  }
}

function App() {
  const [name, setName] = useState("");
  const [chore, setChore] = useState("");
  const [date, setDate] = useState("");
  const [document, setDocument] = useState<ChoreDoc | null>(null);

  const handleNameChange = (e: React.FormEvent<HTMLInputElement>) => {
    e.preventDefault();
    setName(e.currentTarget.value);
  };
  const handleChoreChange = (e: React.FormEvent<HTMLInputElement>) => {
    e.preventDefault();
    setChore(e.currentTarget.value);
  };
  const handleDateChange = (e: React.FormEvent<HTMLInputElement>) => {
    e.preventDefault();
    setDate(e.currentTarget.value);
  };
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    let doc = new ChoreDoc(name, chore, date);

    setDocument(doc);
  };

  return (
    <>
      <div>
        <form className="input-list" onSubmit={handleSubmit}>
          <label>
            Enter Name <br></br>
            <input type="text" name="name" onChange={handleNameChange}></input>
          </label>
          <label>
            Chore <br></br>
            <input
              type="text"
              name="chore"
              onChange={handleChoreChange}
            ></input>
          </label>
          <label>
            Date completed <br></br>
            <input type="text" name="date" onChange={handleDateChange}></input>
          </label>
          <div>
            <button type="submit">Submit</button>
          </div>
        </form>
      </div>
      <div>{document && <Document document={document} />}</div>
    </>
  );
}

export default App;
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! That all makes sense, but why do you set initial state with angled brackets in the followig code: ``` const [document, setDocument] = useState<ChoreDoc | null>(null);```
@JoshSimon No problem! It's to tell TypeScript that either null (the default value) or a ChoreDoc instance will be put in this state variable. If you remove it you will get an error in handleSubmit.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.