TypeScript报错求助:解决GlobalEventHandlers与EventTarget类型属性不存在问题
解决React TypeScript图片上传组件的两个类型错误
错误1:img.onload中this.width/height类型报错
问题原因:用普通函数作为onload回调时,TypeScript会把this推断为GlobalEventHandlers类型,而非我们创建的HTMLImageElement实例,因此无法访问width和height属性。
修改方案:
两种简单解决方式任选其一:
- 改用箭头函数,直接通过作用域内的
img变量访问属性:
img.onload = () => { setWidth(img.width); setHeight(img.height); };
- 给
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类型,定义明确的类型接口:
- 定义组件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) => { ... }
- 修正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
相关产品推荐
相关产品推荐

