typescript 具有TextField轮廓边框的MaterialUI评级组件,键入问题

0sgqnhkj  于 2023-03-04  发布在  TypeScript
关注(0)|答案(1)|浏览(102)

我试图创建一个Rating组件,它的边框带有一个模仿TextField轮廓边框的标签。我找到了this,这个问题几乎涵盖了我想要做的事情,这意味着使用TextFieldinputComponentinputProps来完成它。

import React, { useState } from "react";
import Stack from "@mui/material/Stack";
import Rating from "@mui/material/Rating";
import TextField from "@mui/material/TextField";
import { Favorite, FavoriteBorder } from "@mui/icons-material";

import "./styles.css";

const WrappedRating = React.forwardRef((props, ref) => {
  const { className, onChange, value, ...rest } = props;
  return (
    <div className={className}>
      <Rating
        onChange={(e, value) => {
          console.log("onChange", value);

          onChange({ target: { value: String(value) } });
        }}
        value={Number(value)}
        ref={ref}
        {...rest}
      />
    </div>
  );
});

export default function App() {
  const [value, setValue] = useState();
  const onSubmit = (e) => {
    e.preventDefault();
    console.log(e);
  };

  return (
    <Stack component="form" onSubmit={onSubmit}>
      <TextField
        value={value}
        label="Rating"
        onChange={(e) => {
          console.log("onChange textField", e);
          setValue(e.target.value);
        }}
        InputLabelProps={{
          shrink: true
        }}
        InputProps={{
          inputComponent: WrappedRating,
          inputProps: {
            max: 4,
            onChangeActive: (e, newHover) => {
              //console.log("hover", newHover);
            },
            icon: <Favorite fontSize="inherit" />,
            emptyIcon: <FavoriteBorder fontSize="inherit" />
          }
        }}
      />
    </Stack>
  );
}

CodeSandBox link here
上面的代码可以工作,但我尝试使用TypeScript做同样的事情,而不使用any@ts-ginore

import React, { useState } from "react";
import Stack from "@mui/material/Stack";
import Rating, { RatingProps } from "@mui/material/Rating";
import TextField from "@mui/material/TextField";
import { Favorite, FavoriteBorder } from "@mui/icons-material";
import { InputBaseComponentProps } from "@mui/material";

type WrappedRatingProps = InputBaseComponentProps & RatingProps;

const WrappedRating = React.forwardRef<HTMLInputElement, WrappedRatingProps>(
  (props, ref) => {
    const { className, onChange, value, ...rest } = props;
    return (
      <div className={className}>
        <Rating
          onChange={(e, value) => {
            const event: React.ChangeEvent<HTMLInputElement> = {
              ...e,
              target: {
                value: String(value)
              }
            // Type '{ value: string; }' is not assignable to type 'EventTarget & HTMLInputElement'.
            };
            if (onChange) {
              onChange(event);
            }
          }}
          value={Number(value)}
          ref={ref}
          {...rest}
        />
      </div>
    );
  }
);

export default function App() {
  const [value, setValue] = useState<number>(-1);
  const [hover, setHover] = useState<number>(-1);

  const onSubmit = (e: React.SyntheticEvent) => {
    e.preventDefault();
    console.log(e);
  };

  return (
    <Stack component="form" onSubmit={onSubmit}>
      <TextField
        value={value}
        label="Rating"
        onChange={(e) => {
          setValue(Number(e.target.value));
        }}
        InputLabelProps={{
          shrink: true
        }}
        InputProps={{
          inputComponent: WrappedRating,
          inputProps: {
            max: 4,
            onChangeActive: (e: React.SyntheticEvent, newHover: number) => {
              setHover(newHover);
              console.log(hover);
            },
            icon: <Favorite fontSize="inherit" />,
            emptyIcon: <FavoriteBorder fontSize="inherit" />
          }
        }}
      />
    </Stack>
  );
}

CodeSandBox link here
我已经注意到关于TextField和Rating的值有一个问题,这使得必须转换类型。现在的问题是让onChange工作而不出现类型问题,因为TextFieldRatingonChange期望不同的东西。我试图创建一个新的事件,但它开始变得非常混乱。
有什么想法吗?我知道any@ts-ginore会让这个工作,但我想知道我是否错过了什么。这是我第一次问一个问题,我感谢任何反馈。

js81xvg6

js81xvg61#

我认为onChangevalue的类型已经是string,因为它来自本用例中的输入事件,并且不应该需要通过创建新事件进行额外的转换。
在分叉演示中测试:codesandbox,并且它似乎没有错误。
如果仍然存在关于类型不对齐的问题,是否可能有其他原因?

const WrappedRating = React.forwardRef<HTMLInputElement, WrappedRatingProps>(
  (props, ref) => {
    const { className, value, ...rest } = props;
    return (
      <div className={className}>
        <Rating
          value={Number(value)}
          ref={ref}
          {...rest}
        />
      </div>
    );
  }
);

相关问题