Search code examples
javascriptreactjstypescriptdialog

The expected type comes from property ' ' which is declared here on type 'IntrinsicAttributes & '--prop'


I am trying to pass data from Parent to Child (dialog) component but it considering it as null . The data is coming from api and rendering in the parent component based on id, same data is to be displayed on the form in the dialog when edit button is clicked. It is showing error in Parent Type 'null' is not assignable to type '{ id: number; name: string; email: string; } | undefined'.ts(2322) dialogBox.tsx(13, 3): The expected type comes from property 'postData' which is declared here on type 'IntrinsicAttributes & DialogProps' and in Dialog this error 'postData' is possibly 'undefined'.ts(18048) Parents

interface Post {    
    id: number;
    name: string ;
    email: string; 
  }
  
  export default function ProfileBox2 ()  {
    const [open, setOpen] = React.useState(false);
    const [posts, setPosts] = useState<Post | null>(null);
    const [error, setError] = useState<string | null>(null);

    const handleClickOpen = () => {
        setOpen(true);
      };
    
      const handleClose = () => {
        setOpen(false);
      };
   

    useEffect(() => {
      const fetchData = async () => {
        try {
          const response = await fetch('https://jsonplaceholder.typicode.com/users/1'); 
          if (!response.ok) {
            throw new Error('Failed to fetch post');
          }
          const data: Post = await response.json();
          setPosts(data);
        } catch (error) {
            if (typeof error === 'string') {
              setError(error);
            } else {
              setError('An error occurred while fetching data');
            }
          }
      };
  
      fetchData();
    }, []);
  
  
    return (
      <React.Fragment>
      <div>
        <h1>Profile</h1>
        {error && <div>Error: {error}</div>} 
        {posts && (
        <div>                 
          <p>Name: {posts.name}</p>
          <Divider/>
          <p>Email: {posts.email}</p>
        </div>
      )}
     
      <Button   onClick={handleClickOpen}>Edit</Button> 
      <DialogBox  isOpen={open} postData={posts}/> 
      </div>
      </React.Fragment>
    );    
  };

Dialog (child)

 interface DialogProps {
      isOpen: boolean;
      onClose?: () => void;
      postData? : {    
        id: number;
        name: string;
        email: string; 
      };
    }   
    
      const DialogBox: React.FC<DialogProps> = ({postData , isOpen, onClose}) => {
        const [open, setOpen] = React.useState(false);   
     
        const handleClickOpen = () => {
            setOpen(true);
          };
        
          const handleClose = () => {
            setOpen(false);
          };
          return (
            <React.Fragment>        
            <Dialog
             open={isOpen}
              onClose={handleClose}
              PaperProps={{
                component: 'form',
                onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
                  event.preventDefault();
                  const formData = new FormData(event.currentTarget);
                  const formJson = Object.fromEntries((formData as any).entries());
                  const email = formJson.email;
                  console.log(email);
                  handleClose();
                },
              }}
            >
              <DialogTitle>Dialog </DialogTitle>
              <DialogContent>
                <DialogContentText>
                 Edit Email address
                </DialogContentText>
                {/* {PostData && PostData.email && */}
                <TextField
                  autoFocus
                  required
                  margin="dense"
                  id="name"
                  name="email"
                  label="Email Address"
                  type="email"
                  fullWidth
                  variant="standard" 
                  value = {postData.email}
                />
               {/* } */}
              </DialogContent>
              <DialogActions>
              <Button type="submit">Edit</Button>
                <Button onClick={handleClose}>Cancel</Button>
                
              </DialogActions>
            </Dialog>        
            </React.Fragment>
          );
    }
    
    export default DialogBox;

Solution

  • Things to note:

    1. undefined is not same as null.

    2. The type below expects either no prop (similar to undefined) or the right object:

    postData? : {    
            id: number;
            name: string;
            email: string; 
          }
    

    But, since the initial value of posts is null, you are violating that. So TypeScript complains.

    1. Given your types, where postData can be undefined. The following will break : value = {postData.email}. And that is what typescript is complaining you about.

    2. Update your type to allow null.

    postData : {    
            id: number;
            name: string;
            email: string; 
          } | null
    
    1. Use optional chaining or if conditions to safely access data:
    value = {postData?.email ?? ''}