问题:

类型“Window & typeof globalThis”上不存在属性“my”

但是d.ts已经加了

declare global{

const my:string;

interface Window{ my:string }

}

不加 export {} 扩展不了window吗?

答案:

// global.d.ts(全局声明文件)
declare global {
    const my: string;
    interface Window {
        my: string;  // ❌ 这个扩展实际上不会生效!
    }
}
// 没有 export {},这是一个全局声明文件

为什么需要 export {}

TypeScript 的模块识别规则

// 规则1:如果文件有 import/export → 是模块
// 规则2:如果文件没有 import/export → 是全局脚本

// 全局脚本中的 declare global:
declare global {
    // 这里的内容会被忽略!
    // 因为全局脚本本身就在全局作用域,
    // 不需要 declare global 包装
}

// 模块中的 declare global:
declare global {
    // 这里的内容会被添加到全局作用域
    // 这是 declare global 的正确用法!
}
export {}; // 使文件成为模块

四种情况的对比

情况1:全局文件,直接扩展 Window

// types/global.d.ts(没有 export)
interface Window {
    my: string;  // ✅ 有效,直接扩展
}
// 不需要 declare global
// 使用:window.my

情况2:全局文件,使用 declare global

// types/global.d.ts(没有 export)
declare global {
    interface Window {
        my: string;  // ❌ 无效!会被忽略
    }
}
// 警告:在全局声明文件中不需要 declare global

情况3:模块文件,扩展 Window

// types/window-extensions.d.ts
declare global {
    interface Window {
        my: string;  // ✅ 有效
    }
}
export {}; // ✅ 关键!使文件成为模块

// 使用:window.my

情况4:模块文件,直接扩展 Window(错误)

// types/window-extensions.d.ts
interface Window {
    my: string;  // ❌ 错误!这是局部声明
}
export {}; // 文件是模块

// 这里的 Window 接口是局部类型,
// 不会影响全局的 Window 接口

全局脚本世界(无 import/export)

// 文件:global-script.ts(或 .d.ts)
// 这里写的所有东西都自动在全局作用域

const myGlobal = "hello";  // 自动全局
interface Window {         // 自动扩展全局 Window
    myProp: string;
}

// 这里不需要 declare global,因为本来就在全局!

模块世界(有 import/export)

// 文件:module.ts
// 这里写的所有东西都只在模块内部

const myLocal = "hello";  // 只在模块内可见
interface Window {        // 创建的是局部 Window 类型,不影响全局
    myProp: string;      // 这不是扩展全局 Window!
}

// 如果想影响全局,必须明确声明:
declare global {
    interface Window {   // ✅ 这会扩展到全局
        myProp: string;
    }
}

declare global 的真实含义

// 这句话的意思是:
"虽然我在一个模块里,但我要声明一些全局的东西"

// 所以:
// 在模块中 + declare global = 声明全局内容 ✓
// 在全局中 + declare global = "我在全局中声明全局" ❌(冗余)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐