尝试根据传递给组件的 props 有条件地渲染 JSX 时出现打字稿联合错误

问题描述 投票:0回答:1

我是软件开发和打字稿的新手,所以请原谅我代码中的任何暴行。

** 我有三种类型,其中一种是工会。**

类型.ts

export type CoachType = {
  id: number,
  firstName: string,
  type: string,
  lastName: string,
  email: string,
  city: string,
  state: string,
  picture: string
  reviews: Array<{id: number; title: string; body: string; rating: number; likes: Array<{id: number; agree: boolean}>}>
}

export type ReviewType = {
  id: number,
  rating: number,
  type: string,
  title: string,
  body: string,
  likes: Array<{id: number; agree: boolean}>
}

export type CardType = CoachType | ReviewType;

export type ReviewsInterface = {
  reviews: ReviewType[]
}

**然后,我检查传递给组件的 props,查看 type 属性,以有条件地渲染一些 JSX。 **

index.tsx

import * as React from "react";
import { useNavigate } from "react-router-dom";
import { styled } from "@mui/material/styles";
import Card from "@mui/material/Card";
import CardHeader from "@mui/material/CardHeader";
import CardMedia from "@mui/material/CardMedia";
import CardContent from "@mui/material/CardContent";
import CardActions from "@mui/material/CardActions";
import Avatar from "@mui/material/Avatar";
import IconButton, { IconButtonProps } from "@mui/material/IconButton";
import Typography from "@mui/material/Typography";
import { red } from "@mui/material/colors";
import FavoriteIcon from "@mui/icons-material/Favorite";
import { CardType, ReviewType } from "../../common/types";

interface ExpandMoreProps extends IconButtonProps {
  expand: boolean;
}

const ExpandMore = styled((props: ExpandMoreProps) => {
  const { expand, ...other } = props;
  return <IconButton {...other} />;
})(({ theme, expand }) => ({
  transform: !expand ? "rotate(0deg)" : "rotate(180deg)",
  marginLeft: "auto",
  transition: theme.transitions.create("transform", {
    duration: theme.transitions.duration.shortest,
  }),
}));

export default function CoachCard(props: CardType) {
  const [expanded, setExpanded] = React.useState(false);
  const navigate = useNavigate();

  const averageRating = (reviews: Array<ReviewType>): string => {
    const numberOfRatings = reviews.length;
    let totalOfReviews = 0;
    for (let i = 0; i < numberOfRatings; i++) {
      totalOfReviews += reviews[i].rating;
    }
    const average = totalOfReviews / numberOfRatings;
    return `Average Rating: ${average}/10`;
  };

  const handleExpandClick = () => {
    setExpanded(!expanded);
  };
  console.log(props, "checking props")
  return(
    <>
      { props.type === 'coach' ? (
          <Card sx={{ width: 345 }}>
          <CardHeader
            className="cardHeader"
            onClick={() => navigate(`/coach/${props.id}`)}
            avatar={
              <Avatar sx={{ bgcolor: red[500] }} aria-label="recipe">
                R
              </Avatar>
            }
            title={`${props.firstName} ${props.lastName}`}
            subheader={averageRating(props.reviews)}
          />
          <CardMedia
            component="img"
            height="194"
            image={props.picture}
            alt="Coach"
          />
          <CardContent>
            <Typography variant="body2" color="text.secondary">
              <div>City: {props.city}</div>
              <div>State: {props.state}</div>
              <div>Email: {props.email}</div>
            </Typography>
          </CardContent>
          <CardActions disableSpacing>
            <IconButton aria-label="add to favorites">
              <FavoriteIcon />
            </IconButton>
            <ExpandMore
              expand={expanded}
              onClick={handleExpandClick}
              aria-expanded={expanded}
              aria-label="show more"
            >
              {/* <ExpandMoreIcon /> */}
            </ExpandMore>
          </CardActions>
        </Card>
      ) : (
        <Card sx={{ width: 345 }}>
        <CardHeader
          className="cardHeader"
          onClick={() => navigate(`/coach/${props.id}`)}
          avatar={
            <Avatar sx={{ bgcolor: red[500] }} aria-label="recipe">
              R
            </Avatar>
          }
          title={`${props.firstName} ${props.title}`}
          subheader={props.title}
        />
        <CardContent>
          <Typography variant="body2" color="text.secondary">
            <div>City: {props.title}</div>
            <div>State: {props.body}</div>
            <div>Email: {props.body}</div>
          </Typography>
        </CardContent>
        <CardActions disableSpacing>
          <IconButton aria-label="add to favorites">
            <FavoriteIcon />
          </IconButton>
          <ExpandMore
            expand={expanded}
            onClick={handleExpandClick}
            aria-expanded={expanded}
            aria-label="show more"
          >
            {/* <ExpandMoreIcon /> */}
          </ExpandMore>
        </CardActions>
      </Card>
      )}
    </>
  )
}

它说错了

“CardType”类型上不存在属性“firstName”。 类型“ReviewType”上不存在属性“firstName”。

else 语句中继续出现错误,表示几乎相同,只是 CoachType 和 CardType 上不存在某些道具

我尝试过使用 switch case 和其他条件渲染方法,但没有任何效果。我检查了各种帖子和文档,但无法弄清楚我搞砸了什么。非常感谢任何帮助。

reactjs typescript jsx union-types
1个回答
0
投票

将属性

type
设置为
'coach'
'review'
而不是
string
,例如,对于 Coach Type,不要执行
type: string
放置
type: 'coach'
,然后进行审查
type: 'review'
,这将允许 Typescript 缩小类型。

例如。 打字稿游乐场

© www.soinside.com 2019 - 2024. All rights reserved.