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

如何在TypeScript React项目中无类型错误使用Cloudinary上传组件

Cloudinary上传组件JS转TSX的无类型错误实现方案

我在开发TypeScript+React项目时,需要用Cloudinary实现图片上传并获取图片URL。官方提供的示例是JS版本,转成TSX后出现了类型错误。之前试过用any忽略类型、把var替换成const/let,现在要把CloudinaryUploadWidget.js改成无类型错误的.tsx文件。

修正后的完整TSX代码

import { createContext, useEffect, useState } from "react";

// 定义上下文的类型
type CloudinaryScriptContextType = {
  loaded: boolean;
};

// 创建上下文并指定默认值
const CloudinaryScriptContext = createContext<CloudinaryScriptContextType>({
  loaded: false,
});

// 定义组件Props的类型
interface CloudinaryUploadWidgetProps {
  uwConfig: Parameters<typeof window.cloudinary.createUploadWidget>[0];
  setPublicId: (publicId: string) => void;
}

function CloudinaryUploadWidget({ uwConfig, setPublicId }: CloudinaryUploadWidgetProps) {
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    // 检查脚本是否已加载
    if (!loaded) {
      const uwScript = document.getElementById("uw");
      if (!uwScript) {
        // 未加载则创建并插入脚本
        const script = document.createElement("script");
        script.async = true;
        script.id = "uw";
        script.src = "https://upload-widget.cloudinary.com/global/all.js";
        script.addEventListener("load", () => setLoaded(true));
        document.body.appendChild(script);
      } else {
        // 已加载则更新状态
        setLoaded(true);
      }
    }
  }, [loaded]);

  useEffect(() => {
    if (!loaded) return;

    const widget = window.cloudinary.createUploadWidget(
      uwConfig,
      (error, result) => {
        if (!error && result?.event === "success") {
          console.log("上传完成!图片信息:", result.info);
          setPublicId(result.info.public_id);
        }
      }
    );

    const uploadButton = document.getElementById("upload_widget");
    const handleClick = () => widget.open();

    uploadButton?.addEventListener("click", handleClick);

    // 组件卸载时移除事件监听,避免内存泄漏
    return () => {
      uploadButton?.removeEventListener("click", handleClick);
    };
  }, [loaded, uwConfig, setPublicId]);

  return (
    <CloudinaryScriptContext.Provider value={{ loaded }}>
      <button
        id="upload_widget"
        className="cloudinary-button"
      >
        上传图片
      </button>
    </CloudinaryScriptContext.Provider>
  );
}

export default CloudinaryUploadWidget;
export { CloudinaryScriptContext };

关键改动说明

  • 安装类型定义:先执行npm install @types/cloudinary --save-dev,获取Cloudinary官方类型支持,不用再用any兜底
  • 上下文类型约束:为CloudinaryScriptContext明确指定类型,避免上下文值的类型模糊
  • Props类型复用:用Parameters工具类型直接复用Cloudinary官方的配置类型,确保uwConfig结构合规;同时约束setPublicId的参数为字符串类型
  • 优化事件逻辑:把事件绑定移到独立useEffect中,依赖项更清晰,同时在组件卸载时移除监听,避免重复绑定和内存泄漏
  • 类型安全写法:用result?.event替代result && result.event,更简洁且符合TS语法规范
  • DOM属性优化:把setAttribute("async", "")改成script.async = true,更符合DOM API标准写法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:11:07