You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript报错求助:解决GlobalEventHandlers与EventTarget类型属性不存在问题

解决React TypeScript图片上传组件的两个类型错误

错误1:img.onload中this.width/height类型报错

问题原因:用普通函数作为onload回调时,TypeScript会把this推断为GlobalEventHandlers类型,而非我们创建的HTMLImageElement实例,因此无法访问width和height属性。

修改方案:
两种简单解决方式任选其一:

  1. 改用箭头函数,直接通过作用域内的img变量访问属性:
img.onload = () => {
  setWidth(img.width);
  setHeight(img.height);
};
  1. 给this添加类型断言,明确指定为HTMLImageElement:
img.onload = function(this: HTMLImageElement) {
  setWidth(this.width);
  setHeight(this.height);
};

错误2:onError中e.target.src类型报错

问题原因:EventTarget类型不存在src属性,需要把e.target断言为HTMLImageElement才能访问该属性。

修改方案:
赋值时添加类型断言:

onError={(e) => {
  (e.target as HTMLImageElement).src = defaultPic;
}}

额外类型优化建议(可选)

为了代码更规范,建议替换所有any类型,定义明确的类型接口:

  1. 定义组件Props接口:
interface ImageInputProps {
  name: string;
  onChange: (data: { [key: string]: { data: File; src: string } }) => void;
  showPreview: boolean;
  imageData?: string;
  defaultPic: string;
}

组件声明改为:

const ImageInput = ({ name, onChange, showPreview, imageData, defaultPic }: ImageInputProps) => { ... }
  1. 修正state和函数参数的类型:
const [image, setImage] = useState<File | string>("");
const [height, setHeight] = useState<number | null>(null);
const [width, setWidth] = useState<number | null>(null);
const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => { ... }

修改后的完整代码示例

import React, { useState } from "react";
import "./index.css";

import ImageModal from "../Cropper/imageModal";

interface ImageInputProps {
  name: string;
  onChange: (data: { [key: string]: { data: File; src: string } }) => void;
  showPreview: boolean;
  imageData?: string;
  defaultPic: string;
}

const ImageInput = ({
  name,
  onChange,
  showPreview,
  imageData,
  defaultPic,
}: ImageInputProps) => {
  const [image, setImage] = useState<File | string>("");
  const [modalIsOpen, setModalIsOpen] = useState(false);
  const [height, setHeight] = useState<number | null>(null);
  const [width, setWidth] = useState<number | null>(null);

  const onChangeHandler = (file: File[]) => {
    onChange({
      [name]: {
        data: file[0],
        src: URL.createObjectURL(file[0]),
      },
    });
  };

  const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files?.length > 0) {
      const file = e.target.files;
      const url = URL.createObjectURL(file[0]);
      const img = new Image();
      img.src = url;
      // 解决第一个错误:用箭头函数访问img实例
      img.onload = () => {
        setWidth(img.width);
        setHeight(img.height);
      };
  
      const maxAllowedSize = 5 * 1024 * 1024;
      if (file[0].size > maxAllowedSize) {
        console.log("max image size");
      } else {
          setImage(file[0]);
          setModalIsOpen(true);
      }
      e.target.value = null;
    }
  };

  let inputElement: HTMLInputElement | null = null;

  return (
    <>
      <ImageModal
        modalIsOpen={modalIsOpen}
        closeModal={() => setModalIsOpen(prev => !prev)}
        image={image}
        onCropImage={(croppedImg: File) => onChangeHandler([croppedImg])}
        ratio={height && width ? height / width <= 0.5 : false}
      />
      {showPreview && (
        <div>
            <img
              key={imageData}
              src={imageData || defaultPic}
              className={imageData ? "company-logo" : "default-company-logo"}
              alt="img"
              // 解决第二个错误:类型断言
              onError={(e) => (e.target as HTMLImageElement).src = defaultPic}
            />
        </div>
      )}
      <div className="upload-image" onClick={() => inputElement?.click()}>
        Upload
      </div>
      <input
        ref={input => inputElement = input}
        accept="image/*"
        type="file"
        style={{ display: "none" }}
        onChange={handleFile}
      />
    </>
  );
};

export default ImageInput;

内容的提问来源于stack exchange,提问作者Esther

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:55:21