如何在 TypeScript 中显式设置“window”的新属性?
-
13-12-2019 - |
题
我通过显式设置属性来为我的对象设置全局命名空间 window
.
window.MyNamespace = window.MyNamespace || {};
TypeScript 下划线 MyNamespace
并抱怨说:
属性“ mynamespace”不存在于类型的“窗口”的价值上
我可以通过声明使代码工作 MyNamespace
作为环境变量并删除 window
明确,但我不想这样做。
declare var MyNamespace: any;
MyNamespace = MyNamespace || {};
我怎样才能保留 window
在那里并让 TypeScript 高兴?
顺便说一句,我发现 TypeScript 的抱怨特别有趣,因为它告诉我 window
属于类型 any
其中绝对可以包含任何东西。
解决方案
刚刚找到了这个问题的答案 另一个 StackOverflow 问题的答案.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
基本上你需要扩展现有的 window
界面告诉它你的新属性。
其他提示
为了保持动态,只需使用:
(<any>window).MyNamespace
自 Typescript ^3.4.3 起,此解决方案不再有效
或者...
您只需输入:
window['MyNamespace']
你不会得到编译错误,它的工作原理与键入相同 window.MyNamespace
使用多伦多证券交易所?其他答案都不适合我。
这就是我所做的:
(window as any).MyNamespace
接受的答案是我曾经使用过的,但对于 TypeScript 0.9.* 它不再有效。新的定义 Window
接口似乎完全取代了内置定义,而不是增强它。
我已经开始这样做:
interface MyWindow extends Window {
myFunction(): void;
}
declare var window: MyWindow;
更新: 在 TypeScript 0.9.5 中,接受的答案再次起作用。
全球都是“邪恶的”:),我认为同时具有可移植性的最佳方法是:
首先导出接口:(例如:./custom.window.ts)
export interface CustomWindow extends Window {
customAttribute: any;
}
其次你导入
import {CustomWindow} from './custom.window.ts';
第三个带有 CustomWindow 的全局变量窗口
declare let window: CustomWindow;
这样,如果您使用窗口对象的现有属性,则在不同的 IDE 中也不会出现红线,因此最后尝试:
window.customAttribute = 'works';
window.location.href = '/works';
使用 Typescript 2.4.x 和最新版本进行测试!
如果您需要延长 window
具有需要使用的自定义类型的对象 import
您可以使用以下方法:
窗口.d.ts
import MyInterface from './MyInterface';
declare global {
interface Window {
propName: MyInterface
}
}
请参阅手册“声明合并”部分中的“全局增强”: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation
我不需要经常这样做,我遇到的唯一情况是使用 Redux Devtools 和中间件时。
我只是做了:
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
或者你可以这样做:
let myWindow = window as any;
进而 myWindow.myProp = 'my value';
对于那些使用 角度 CLI 这很简单:
src/polyfills.ts
declare global {
interface Window {
myCustomFn: () => void;
}
}
my-custom-utils.ts
window.myCustomFn = function () {
...
};
如果您使用的是 IntelliJ,则还需要在使用新的 polyfill 之前更改 IDE 中的以下设置:
> File
> Settings
> Languages & Frameworks
> TypeScript
> check 'Use TypeScript Service'.
大多数其他答案并不完美。
- 其中一些只是抑制了商店的类型推断。
- 其他一些只关心全局变量作为命名空间,而不是作为接口/类
今天早上我也遇到了类似的问题。我在 SO 上尝试了很多“解决方案”,但没有一个绝对不会产生类型错误并在 IDE(webstorm 或 vscode)中启用触发类型跳转。
最后,从这里开始
https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-102523512
, ,我找到了一个合理的解决方案 附加全局变量的类型,该变量充当接口/类和命名空间.
示例如下:
// typings.d.ts
declare interface Window {
myNamespace?: MyNamespace & typeof MyNamespace
}
declare interface MyNamespace {
somemethod?()
}
declare namespace MyNamespace {
// ...
}
现在,上面的代码合并了命名空间的类型 MyNamespace
和接口 MyNamespace
进入全局变量 myNamespace
(窗口的属性)。
在找到答案后,我认为此页面可能会有所帮助。https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation不确定声明合并的历史,但它解释了为什么以下可以起作用。
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
如果您正在使用,请按以下步骤操作 TypeScript 定义管理器!
npm install typings --global
创造 typings/custom/window.d.ts
:
interface Window {
MyNamespace: any;
}
declare var window: Window;
安装您的自定义打字:
typings install file:typings/custom/window.d.ts --save --global
完成,使用它! Typescript 不会再抱怨了:
window.MyNamespace = window.MyNamespace || {};
如果您使用的是 Typescript 3.x,您可以省略 declare global
参与其他答案,而只需使用:
interface Window {
someValue: string
another: boolean
}
当我使用 Typescript 3.3、WebPack 和 TSLint 时,这对我很有用。
Tyscript 不对字符串属性执行类型检查。
window["newProperty"] = customObj;
理想情况下,应该避免全局变量的情况。我有时用它来调试浏览器控制台中的对象。
供参考(这是正确答案):
里面一个 .d.ts
定义文件
type MyGlobalFunctionType = (name: string) => void
如果您在浏览器中工作,则通过重新打开窗口的界面来将成员添加到浏览器的窗口上下文中:
interface Window {
myGlobalFunction: MyGlobalFunctionType
}
NodeJS 的想法相同:
declare module NodeJS {
interface Global {
myGlobalFunction: MyGlobalFunctionType
}
}
现在您声明根变量(实际上将存在于窗口或全局变量中)
declare const myGlobalFunction: MyGlobalFunctionType;
然后在常规的 .ts
文件,但作为副作用导入,您实际上实现它:
global/* or window */.myGlobalFunction = function (name: string) {
console.log("Hey !", name);
};
最后在代码库的其他地方使用它,可以使用:
global/* or window */.myGlobalFunction("Kevin");
myGlobalFunction("Kevin");
创建一个自定义界面来扩展窗口并添加您的自定义属性作为可选。
然后,让customWindow使用自定义界面,但以原始窗口赋值。
它与 typescript@3.1.3 一起使用。
interface ICustomWindow extends Window {
MyNamespace?: any
}
const customWindow:ICustomWindow = window;
customWindow.MyNamespace = customWindow.MyNamespace {}
对于那些想要设置计算或动态属性的人 window
对象,你会发现这是不可能的 declare global
方法。为了澄清这个用例
window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature
你可能会尝试做这样的事情
declare global {
interface Window {
[DyanmicObject.key]: string; // error RIP
}
}
但上面会出错。这是因为在 Typescript 中,接口不能很好地处理计算属性,并且会抛出类似的错误
A computed property name in an interface must directly refer to a built-in symbol
为了解决这个问题,您可以采用强制转换的建议 window
到 <any>
所以你可以做
(window as any)[DynamicObject.key]
我今天想在 Angular (6) 库中使用它,我花了一段时间才让它按预期工作。
为了让我的库使用声明,我必须使用 d.ts
声明全局对象新属性的文件的扩展名。
所以最后,文件的结果是这样的:
/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts
创建后,不要忘记将其公开在您的 public_api.ts
.
那对我来说是这样的。希望这可以帮助。
首先,您需要在当前范围内声明窗口对象。
因为打字稿想知道对象的类型。
由于窗口对象是在其他地方定义的,因此您无法重新定义它。
但您可以按如下方式声明:-
declare var window: any;
这不会重新定义窗口对象,也不会创建另一个具有名称的变量 window
.
这意味着 window 是在其他地方定义的,而您只是在当前范围内引用它。
然后您可以通过以下方式引用您的 MyNamespace 对象:-
window.MyNamespace
或者您可以将新属性设置为 window
对象只需:-
window.MyNamespace = MyObject
现在打字稿不会抱怨了。