TypeScriptの `window`に新しいプロパティを明示的に設定するにはどうすればよいですか?


621

にプロパティを明示的に設定することにより、オブジェクトのグローバル名前空間を設定しますwindow

window.MyNamespace = window.MyNamespace || {};

TypeScriptは次のことを強調しMyNamespace、不満を述べています:

プロパティ 'MyNamespace'はタイプ 'ウィンドウ'の値には存在しません

MyNamespaceアンビエント変数として宣言し、window明示性を削除することでコードを機能させることができますが、それはしたくありません。

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

どのように私windowはそこに留まり、TypeScriptを幸せにすることができますか?

余談ですが、TypeScript windowany間違いなく何かを含むことができる型であると告げるので、TypeScriptが文句を言うのは特に面白いと思います。


回答:


692

StackOverflowの別の質問の回答でこれに対する答えを見つけました。

declare global {
    interface Window { MyNamespace: any; }
}

window.MyNamespace = window.MyNamespace || {};

基本的には、既存のwindowインターフェースを拡張して、新しいプロパティについて通知する必要があります。


12
ウィンドウの大文字のWに注意してください。それは私をつまずかせました。
ajm 2013年

2
これをtsc 1.0.1.0でコンパイルすることができませんでした。しかし、ブレイク・ミッチェルの答えは私には役立った。
Pat

43
これは、別の.d.tsファイルで宣言されている場合にのみ機能することに注意してください。.tsインポートおよびエクスポート自体を使用するファイルで使用すると機能しません。この回答を参照してください。
cdauth 2016年

36
declare global { interface Window { ... } }活字体2.5.2、を必要とせず、作品.d.ts上述したように、ファイル
tanguy_k

2
最初にタイプスクリプトは私に言った:error TS1234: An ambient module declaration is only allowed at the top level in a file.、それをファイルの先頭に置いたとき、それはそのエラーを修正したので、あなたもそれをする必要があるかもしれません。
Zelphir Kaltstahl 2017年

397

動的に保つには、次のように使用します。

(<any>window).MyNamespace

9
これをtsxファイルで行う方法はありますか?
ベロップ2017年

2
@martin:<any>はそれを明示的にするので、うまく機能すると思います。その他:Reactまたはその他のJSX環境でTypescriptを使用している場合(TSX構文になる)、のas代わりに使用する必要があり<>ます。以下の@ david-boydの回答を参照してください
Don

31
MyNamespace
Arsalan Ahmad

同様のためにthis-return (<any> this)['something in scope']
HankCa

1
私はその行でtslintを無効にする必要がありました/* tslint:disable */
Michael Yagudaev

197

TYPESCRIPT現在^ 3.4.3このソリューションは機能しなくなりました

または...

あなたはただタイプすることができます:

window['MyNamespace']

コンパイルエラーは発生せず、タイピングと同じように機能します window.MyNamespace


15
しかし、おそらくtslintエラーが発生します...もちろん、もしあれば
smnbbrv

69
これは、TypeScriptの背後にある全体的なアイデアである強力なタイピングに完全に対応しています。
d512

18
@ user1334007もグローバルを使用しています。ただし、一部のレガシーコードでは必要です。
nathancahill

3
@Ramesh window['MyNamespace']()(角かっこを追加するだけ)
iBaff

6
「これは強力なタイピング、TypeScriptの背後にある全体的な考えに直面して完全に飛んでいます。」良い!
コーディ

188

TSXを使用していますか?他の答えはどれも私のために働いていませんでした。

これが私がしたことです:

(window as any).MyNamespace


44
<any>型キャストではなくJSXとして解釈されるため、TSXを使用する場合を除いて同じです。
ジェイクブーン2017年

1
@Davidに感謝します。これは新しいCreate React Appとtypescriptバージョンの魅力のように機能しました。以前はこれが機能していました:(<any> window).MyNamespaceが、新しいtypescriptバージョン3.5.xで機能しなくなっています。
Jignesh Raval

いずれかのウィンドウ?では、なぜtypescriptを使うのでしょうか?Javascript x)を使用してください
MarcoLe

71

受け入れられた答えは以前使用していたものですが、TypeScript 0.9。*では機能しなくなりました。の新しい定義Windowインターフェース組み込みの定義を拡張するのではなく、完全に置き換えるようです。

代わりにこれを行うことにしました:

interface MyWindow extends Window {
    myFunction(): void;
}

declare var window: MyWindow;

更新: TypeScript 0.9.5では、受け入れられた回答が再び機能します。


2
これは、TypeScript 2.0.8で使用されるモジュールでも機能します。例:export default class MyClass{ foo(){ ... } ... } interface MyWindow extends Window{ mc: MyClass } declare var window: MyWindow window.mc = new MyClass() 次に、foo()を呼び出すことができます。例: Chrome Dev Toolsコンソールから mc.foo()
Martin Majewski

何かをグローバルとして宣言したくない場合、これは非常に良い答えです。反対に、必要なdeclare var...すべてのファイルを呼び出す必要があります。
Puce

さらに、このアプローチでは、monorepoのグローバルウィンドウを拡張する他のパッケージと競合しないためです。
Dmitrii Sorin 2018

ありがとうございました!ベストアンサーIMO。バニラウィンドウWindowはないという単純な事実を無視してはなりません。型チェックを回避したり、TSをだますことも、それを行う方法ではありません。
Rutger Willems

これは、残念ながら、TS 3.6のように動作しません
ヤコブSoderlundに

65

グローバルは "悪"です:)、私は移植性も持つ最善の方法は次のとおりです。

まず、インターフェースをエクスポートします(例:./custom.window.ts)

export interface CustomWindow extends Window {
    customAttribute: any;
}

次にインポートします

import {CustomWindow} from './custom.window.ts';

CustomWindowを使用した3番目のキャストグローバル変数ウィンドウ

declare let window: CustomWindow;

このように、ウィンドウオブジェクトの既存の属性を使用する場合、別のIDEに赤い線が表示されないので、最後に次のことを試してください。

window.customAttribute = 'works';
window.location.href = '/works';

Typescript 2.4.x以降でテスト済み!


1
グローバルが悪である理由を詳しく説明することもできます。私たちのケースでは、ウィンドウオブジェクトで標準化されていないAPIを使用しています。現時点ではポリフィルされています。それは本当に悪ですか?
Mathijs Segers 2018年

1
@MathijsSegers私は特にあなたのケースを知りませんが、グローバルについて悪いことはjavascriptについてだけではありません..すべての言語である..いくつかの理由があります:-デザインパターンをうまく適用できない-メモリとパフォーマンスの問題(それらをどこにでも持って、文字列オブジェクトに何かをアタッチして、新しい文字列を実行したときに何が起こるかを確認してください)-コードに副作用を引き起こす名前の衝突..(特に非同期の性質を持つjavascriptの場合)続行できますが、残り...
onalbi

1
@onabi私は文字通りブラウザの機能について話している。ブラウザなので、世界中で利用できます。あなたは本当にグローバルな定義に行くのはまだ間違っていることを示唆しますか?つまり、Ponyfillsを実装することはできますが、これは実際に機能をサポートするブラウザ(たとえば、フルスクリーンAPI)を膨らませることになります。そうは言っても、すべてのグローバルが悪の勢力であるとは信じていません。
Mathijs Segers

2
@MathijsSegers私の意見では、グローバル変数はできる限り使用または変更しないようにする必要があります..ブラウザーが存在するのでウィンドウが利用できることはtrueですが、常に変化していたことも当てはまります。 window.feature = '機能'; そして、これはコードで大量に使用されます。すべてのコードでwindow.featureがブラウザによって追加された場合、この機能はオーバーライドされます。どうせ私は私の文章の説明をあなたに反することではありません。
onalbi 2018年

48

windowの使用が必要なカスタムタイプでオブジェクトを拡張する必要がある場合import、次のメソッドを使用できます。

window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

ハンドブックの「宣言のマージ」セクションの「グローバル拡張」を参照してください:https : //www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation


43

Angular CLIを使用している人にとっては簡単です:

src / polyfills.ts

declare global {
  interface Window {
    myCustomFn: () => void;
  }
}

my-custom-utils.ts

window.myCustomFn = function () {
  ...
};

IntelliJを使用している場合は、新しいポリフィルをピックアップする前に、IDEで次の設定を変更する必要もあります。

> File 
> Settings 
> Languages & Frameworks 
> TypeScript 
> check 'Use TypeScript Service'.

1
declare globalがトリックであり、この回答は実際にはAngular CLIに固有のものではありません...
Avindra Goolcharan

31

私はこれを頻繁に行う必要はありません。唯一のケースは、ミドルウェアでRedux Devtoolsを使用する場合でした。

私は単にしました:

const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

またはあなたがすることができます:

let myWindow = window as any;

その後 myWindow.myProp = 'my value';



あなたはこれを行うことができますが、それは質問への答えではなく、回避策はありません
Vitalij

これのおかげで、私は(どのようウィンドウ)を使用して、適切にtypescriptです下Reduxのツールを有効にすることができ.__ REDUX_DEVTOOLS_EXTENSION__ && .__ REDUX_DEVTOOLS_EXTENSION __())(いずれかのようなウィンドウ)
danivicario

20

他の答えのほとんどは完璧ではありません。

  • それらのいくつかは単にショップの型推論を抑制します。
  • 他の一部はグローバル変数のみをネームスペースとして扱い、インターフェース/クラスとしては扱いません

今朝も同様の問題に遭遇しました。私は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(ウィンドウのプロパティ)にマージします。


2
ありがとう-これは、モジュール以外のアンビエントコンテキストで一見使用できる唯一のものです。
タイラーセバスチャン


13

TypeScript Definition Managerを使用している場合の方法は次のとおりです

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 || {};

1
FWIW typingsはTypescript 2.0(2016年半ば)で廃止され、所有者によってアーカイブされました。
mrm 2018

13

Typscriptは文字列プロパティのタイプチェックを実行しません。

window["newProperty"] = customObj;

理想的には、グローバル変数シナリオは回避する必要があります。ブラウザコンソールでオブジェクトをデバッグするために時々使用します。



8

Typescript 3.xを使用している場合declare globalは、他の回答の一部を省略して、代わりに次のように使用できる場合があります。

interface Window {
  someValue: string
  another: boolean
}

Typescript 3.3、WebPack、およびTSLintを使用している場合、これは私と一緒に機能しました。


では機能しません^3.4.3。この答えは私にとってうまくいき
Green

7

参考までに(これが正解です):

内側の.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");

おかげで、これは私が見つけた最高の例であり、うまく機能しています。
Nick G.

6

カスタムインターフェイスを作成してウィンドウを拡張し、カスタムプロパティをオプションとして追加します。

次に、カスタムインターフェースを使用するcustomWindowに、元のウィンドウで評価されるようにします。

typescript@3.1.3で動作します。

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 

5

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]

3
これは2019年そうです
QWERTY配列の

4

create-react-app v3.3を使用して、これを実現する最も簡単な方法Windowは、自動生成されたタイプを拡張することでしたreact-app-env.d.ts

interface Window {
    MyNamespace: any;
}

3

最初に、現在のスコープでウィンドウオブジェクトを宣言する必要があります。
typescriptはオブジェクトのタイプを知りたいからです。
ウィンドウオブジェクトは他の場所で定義されているため、再定義できません。
ただし、次のように宣言できます。

declare var window: any;

これはウィンドウオブジェクトを再定義しないか、名前を持つ別の変数を作成しませんwindow
これは、ウィンドウが別の場所で定義されていて、現在のスコープで参照しているだけであることを意味します。

その後、次の方法でMyNamespaceオブジェクトを参照できます。

window.MyNamespace

または、window単に次の方法でオブジェクトに新しいプロパティを設定できます。

window.MyNamespace = MyObject

そして今、タイプスクリプトは文句を言わないでしょう。


どこwindowが定義されているのか知りたいユースケースを教えてください。
Mav55

2

今日、これをAngular(6)ライブラリで使用したかったのですが、期待どおりに機能するまでに少し時間がかかりました。

ライブラリで宣言を使用するにd.tsは、グローバルオブジェクトの新しいプロパティを宣言するファイルの拡張を使用する必要がありました。

つまり、最終的にファイルは次のようになります。

/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts

作成したら、で公開することを忘れないでくださいpublic_api.ts

それは私のためにそれをしました。お役に立てれば。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.