Wie legt man in TypeScript explizit eine neue Eigenschaft für „window“ fest?
-
13-12-2019 - |
Frage
Ich richte globale Namespaces für meine Objekte ein, indem ich explizit eine Eigenschaft festlege window
.
window.MyNamespace = window.MyNamespace || {};
TypeScript unterstreicht MyNamespace
und beschwert sich darüber:
Die Eigenschaft 'mynamesspace' existiert nicht im Wert des Typs 'Fenster' Any ".
Ich kann dafür sorgen, dass der Code funktioniert, indem ich ihn deklariere MyNamespace
als Umgebungsvariable und Löschen der window
Explizitheit, aber das möchte ich nicht tun.
declare var MyNamespace: any;
MyNamespace = MyNamespace || {};
Wie kann ich behalten window
rein und TypeScript glücklich machen?
Nebenbei bemerkt finde ich es besonders lustig, dass sich TypeScript beschwert, da es mir das sagt window
ist vom Typ any
was definitiv alles enthalten kann.
Lösung
Habe gerade die Antwort darauf gefunden Die Antwort auf eine weitere StackOverflow-Frage.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
Grundsätzlich müssen Sie das Bestehende erweitern window
Schnittstelle, um es über Ihre neue Immobilie zu informieren.
Andere Tipps
Um es dynamisch zu halten, verwenden Sie einfach:
(<any>window).MyNamespace
AB TYPESCRIPT ^3.4.3 FUNKTIONIERT DIESE LÖSUNG NICHT MEHR
Oder...
Sie können einfach Folgendes eingeben:
window['MyNamespace']
und Sie erhalten keinen Kompilierungsfehler und es funktioniert genauso wie beim Tippen window.MyNamespace
Verwenden Sie TSX?Keine der anderen Antworten funktionierte für mich.
Folgendes habe ich getan:
(window as any).MyNamespace
Die akzeptierte Antwort ist die, die ich früher verwendet habe, aber mit TypeScript 0.9.* funktioniert es nicht mehr.Die neue Definition der Window
Die Schnittstelle scheint die integrierte Definition vollständig zu ersetzen, anstatt sie zu erweitern.
Ich habe stattdessen Folgendes getan:
interface MyWindow extends Window {
myFunction(): void;
}
declare var window: MyWindow;
AKTUALISIEREN: Mit TypeScript 0.9.5 funktioniert die akzeptierte Antwort wieder.
Global sind „böse“ :), ich denke, der beste Weg, auch die Portabilität zu gewährleisten, ist:
Zuerst exportieren Sie die Schnittstelle:(z.B:./custom.window.ts)
export interface CustomWindow extends Window {
customAttribute: any;
}
Zweitens importieren Sie
import {CustomWindow} from './custom.window.ts';
Drittes globales Variablenfenster mit CustomWindow umwandeln
declare let window: CustomWindow;
Auf diese Weise haben Sie nicht auch eine rote Linie in einer anderen IDE, wenn Sie sie mit vorhandenen Attributen eines Fensterobjekts verwenden. Versuchen Sie es also am Ende:
window.customAttribute = 'works';
window.location.href = '/works';
Getestet mit Typescript 2.4.x und neu!
Wenn Sie die erweitern müssen window
Objekt mit einem benutzerdefinierten Typ, der die Verwendung von erfordert import
Sie können die folgende Methode verwenden:
window.d.ts
import MyInterface from './MyInterface';
declare global {
interface Window {
propName: MyInterface
}
}
Siehe „Globale Augmentation“ im Abschnitt „Deklarationszusammenführung“ des Handbuchs: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation
Ich muss das nicht sehr oft tun, der einzige Fall, den ich hatte, war die Verwendung von Redux Devtools mit Middleware.
Ich habe einfach Folgendes getan:
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
Oder Sie könnten Folgendes tun:
let myWindow = window as any;
und dann myWindow.myProp = 'my value';
Für diejenigen, die das verwenden Angular CLI es ist ganz einfach:
src/polyfills.ts
declare global {
interface Window {
myCustomFn: () => void;
}
}
my-custom-utils.ts
window.myCustomFn = function () {
...
};
Wenn Sie IntelliJ verwenden, mussten Sie außerdem die folgende Einstellung in der IDE ändern, bevor Ihre neuen Polyfills wirksam werden:
> File
> Settings
> Languages & Frameworks
> TypeScript
> check 'Use TypeScript Service'.
Die meisten anderen Antworten sind nicht perfekt.
- Einige von ihnen unterdrücken einfach die Typinferenz für Shop.
- Einige andere kümmern sich nur um globale Variablen als Namespace, nicht jedoch um Schnittstellen/Klassen
Ich bin heute Morgen auch auf ein ähnliches Problem gestoßen.Ich habe so viele „Lösungen“ für SO ausprobiert, aber keine davon erzeugt absolut keinen Typfehler und ermöglicht das Auslösen von Typsprüngen in der IDE (Webstorm oder vscode).
Endlich von hier aus
https://github.com/Microsoft/TypeScript/issues/3180#issuecomment -102523512
, ich finde eine vernünftige Lösung dafür Hängen Sie Typisierungen für globale Variablen an, die sowohl als Schnittstelle/Klasse als auch als Namespace fungieren.
Beispiel ist unten:
// typings.d.ts
declare interface Window {
myNamespace?: MyNamespace & typeof MyNamespace
}
declare interface MyNamespace {
somemethod?()
}
declare namespace MyNamespace {
// ...
}
Der obige Code führt nun die Typisierungen des Namespace zusammen MyNamespace
und Schnittstelle MyNamespace
in die globale Variable myNamespace
(die Eigenschaft von Fenster).
Nachdem ich Antworten gefunden habe, denke ich, dass diese Seite hilfreich sein könnte.https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentationIch bin mir über die Geschichte der Zusammenführung von Deklarationen nicht sicher, aber es erklärt, warum das Folgende funktionieren könnte.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
Hier erfahren Sie, wie es geht, wenn Sie es verwenden TypeScript-Definitionsmanager!
npm install typings --global
Erstellen typings/custom/window.d.ts
:
interface Window {
MyNamespace: any;
}
declare var window: Window;
Installieren Sie Ihre benutzerdefinierte Eingabe:
typings install file:typings/custom/window.d.ts --save --global
Fertig, verwenden Sie es! Typescript wird sich nicht mehr beschweren:
window.MyNamespace = window.MyNamespace || {};
Wenn Sie Typescript 3.x verwenden, können Sie möglicherweise darauf verzichten declare global
Teil in den anderen Antworten und verwenden Sie stattdessen einfach:
interface Window {
someValue: string
another: boolean
}
Dies funktionierte bei mir, als ich Typescript 3.3, WebPack und TSLint verwendete.
Typscript führt keine Typprüfung für Zeichenfolgeneigenschaften durch.
window["newProperty"] = customObj;
Idealerweise sollte das Szenario mit globalen Variablen vermieden werden.Ich verwende es manchmal, um ein Objekt in der Browserkonsole zu debuggen.
Als Referenz (dies ist die richtige Antwort):
In einem .d.ts
Definitionsdatei
type MyGlobalFunctionType = (name: string) => void
Wenn Sie im Browser arbeiten, fügen Sie Mitglieder zum Fensterkontext des Browsers hinzu, indem Sie die Schnittstelle des Fensters wiedereröffnen:
interface Window {
myGlobalFunction: MyGlobalFunctionType
}
Gleiche Idee für NodeJS:
declare module NodeJS {
interface Global {
myGlobalFunction: MyGlobalFunctionType
}
}
Jetzt deklarieren Sie die Stammvariable (die tatsächlich im Fenster oder global leben wird).
declare const myGlobalFunction: MyGlobalFunctionType;
Dann in einem regulären .ts
Datei, aber als Nebeneffekt importiert, implementieren Sie sie tatsächlich:
global/* or window */.myGlobalFunction = function (name: string) {
console.log("Hey !", name);
};
Und schließlich an anderer Stelle in der Codebasis verwenden, entweder mit:
global/* or window */.myGlobalFunction("Kevin");
myGlobalFunction("Kevin");
Erstellen Sie eine benutzerdefinierte Schnittstelle, die das Fenster erweitert, und fügen Sie Ihre benutzerdefinierte Eigenschaft optional hinzu.
Lassen Sie dann das benutzerdefinierte Fenster die benutzerdefinierte Schnittstelle verwenden, werten Sie es jedoch mit dem Originalfenster aus.
Es hat mit dem Typescript@3.1.3 funktioniert.
interface ICustomWindow extends Window {
MyNamespace?: any
}
const customWindow:ICustomWindow = window;
customWindow.MyNamespace = customWindow.MyNamespace {}
Für diejenigen, die eine berechnete oder dynamische Eigenschaft festlegen möchten window
Objekt, Sie werden feststellen, dass das mit dem nicht möglich ist declare global
Methode.Zur Verdeutlichung für diesen Anwendungsfall
window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature
Sie könnten versuchen, so etwas zu tun
declare global {
interface Window {
[DyanmicObject.key]: string; // error RIP
}
}
Das Obige führt jedoch zu einem Fehler.Dies liegt daran, dass Schnittstellen in Typescript nicht gut mit berechneten Eigenschaften funktionieren und einen Fehler wie „
A computed property name in an interface must directly refer to a built-in symbol
Um dies zu umgehen, können Sie auf den Casting-Vorschlag zurückgreifen window
Zu <any>
so können Sie es tun
(window as any)[DynamicObject.key]
Ich wollte dies heute in einer Angular (6)-Bibliothek verwenden und es hat eine Weile gedauert, bis es wie erwartet funktionierte.
Damit meine Bibliothek Deklarationen verwenden konnte, musste ich die verwenden d.ts
Erweiterung für die Datei, die die neuen Eigenschaften des globalen Objekts deklariert.
Am Ende hatte die Datei also etwas wie:
/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts
Vergessen Sie nicht, es nach der Erstellung in Ihrem Browser verfügbar zu machen public_api.ts
.
Das hat es für mich getan.Hoffe das hilft.
Zuerst müssen Sie das Fensterobjekt im aktuellen Bereich deklarieren.
Denn Typescript möchte den Typ des Objekts wissen.
Da das Fensterobjekt an einer anderen Stelle definiert ist, können Sie es nicht neu definieren.
Aber Sie können es wie folgt deklarieren:-
declare var window: any;
Dadurch wird das Fensterobjekt nicht neu definiert oder es wird keine weitere Variable mit Namen erstellt window
.
Das bedeutet, dass das Fenster an einer anderen Stelle definiert ist und Sie nur im aktuellen Bereich darauf verweisen.
Dann können Sie einfach auf Ihr MyNamespace-Objekt verweisen:
window.MyNamespace
Oder Sie können die neue Eigenschaft aktivieren window
Objekt einfach durch:-
window.MyNamespace = MyObject
Und jetzt wird sich das Typoskript nicht beschweren.