web-dev-qa-db-fra.com

Comment définir explicitement une nouvelle propriété sur `window` dans TypeScript?

Je configure des espaces de noms globaux pour mes objets en définissant explicitement une propriété sur window.

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

TypeScript souligne MyNamespace et se plaint de ce qui suit:

La propriété 'MyNamespace' n'existe pas sur la valeur de type 'window' tout"

Je peux faire fonctionner le code en déclarant MyNamespace en tant que variable ambiante et en supprimant le caractère explicite de window mais je ne veux pas le faire.

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

Comment puis-je conserver window et rendre TypeScript heureux?

En remarque, je trouve particulièrement drôle que TypeScript se plaint, car il me dit que window est de type any et qu'il peut certainement contenir n'importe quoi.

354
joshuapoehls

Je viens de trouver la réponse à ceci dans la réponse à une autre question StackOverflow .

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

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

Fondamentalement, vous devez étendre l’interface window existante pour la renseigner sur votre nouvelle propriété.

359
joshuapoehls

Pour rester dynamique, utilisez simplement:

(<any>window).MyNamespace
316
chinupson

Ou...

vous pouvez simplement taper:

window['MyNamespace']

et vous n'obtiendrez pas d'erreur de compilation et cela fonctionne de la même manière que si vous tapiez window.MyNamespace

158
Evan Larsen

Vous utilisez TSX? Aucune des autres réponses ne fonctionnait pour moi. 

Voici ce que j'ai fait:

(window as any).MyNamespace
125
David Boyd

La réponse acceptée est celle que j’avais l'habitude d'utiliser, mais avec TypeScript 0.9. * Cela ne fonctionne plus. La nouvelle définition de l'interface Window semble remplacer complètement la définition intégrée, au lieu de l'augmenter.

J'ai pris à faire cela à la place:

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

declare var window: MyWindow;

UPDATE: Avec TypeScript 0.9.5, la réponse acceptée fonctionne à nouveau.

53
Blake Mitchell

Si vous devez étendre l'objet window avec un type personnalisé nécessitant l'utilisation de import, vous pouvez utiliser la méthode suivante:

window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

Voir «Augmentation globale» dans la section «Déclaration» du manuel: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation

36
Lucifer Sam

Global are "evil" :), je pense que la meilleure façon d’avoir la portabilité est:

D'abord, vous exportez l'interface: (par exemple: ./custom.window.ts)

export interface CustomWindow extends Window {
    customAttribute: any;
}

Deuxièmement, vous importez

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

Troisième fenêtre var de distribution globale avec CustomWindow

declare let window: CustomWindow;

De cette manière, vous n'avez pas non plus de ligne rouge dans différents IDE si vous utilisez des attributs existants d'un objet window, aussi essayez-vous à la fin:

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

Testé avec TypeScript 2.4.x

28
onalbi

Je n'ai pas besoin de le faire très souvent, le seul cas que j'ai eu concernait l'utilisation de Redux Devtools avec un middleware.

J'ai simplement fait:

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

Ou tu pourrais faire:

let myWindow = window as any;

et ensuite myWindow.myProp = 'my value';

19
Dimitar Nikovski

La plupart des autres réponses ne sont pas parfaites.

  • Certains d'entre eux suppriment simplement l'inférence de type pour shop.
  • Certains des autres ne se préoccupent que de la variable globale en tant qu'espace de nom, mais pas en tant qu'interface/classe

Je rencontre aussi le même problème ce matin. J'ai essayé autant de "solutions" sur SO, mais aucune d'entre elles ne produisait absolument d'erreur de type et permettait de déclencher le saut de type dans IDE (webstorm ou vscode). 

Enfin, d'ici

https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-102523512

, Je trouve une solution raisonnable à attach typings pour la variable globale qui fait office d’interface/classe et d’espace de nom.

Exemple est ci-dessous:

// typings.d.ts
declare interface Window {
    myNamespace?: MyNamespace & typeof MyNamespace
}

declare interface MyNamespace {
    somemethod?()
}

declare namespace MyNamespace {
    // ...
}

Désormais, le code ci-dessus fusionne les typages d'espace de nom MyNamespace et d'interface MyNamespace dans la variable globale myNamespace (la propriété de window).

10
e-cloud

Si vous utilisez le CLI angulaire c'est vraiment simple:

src/polyfills.ts

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

my-custom-utils.ts

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

Si vous utilisez IntelliJ, vous deviez également modifier le paramètre suivant dans IDE avant la reprise de votre nouveau remplissage multiple:

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

Voici comment procéder, si vous utilisez TypeScript Definition Manager!

npm install typings --global

Créer typings/custom/window.d.ts:

interface Window {
  MyNamespace: any;
}

declare var window: Window;

Installez votre saisie personnalisée: 

typings install file:typings/custom/window.d.ts --save --global

Fait, utilise it‌! TypeScript ne se plaindra plus:

window.MyNamespace = window.MyNamespace || {};
8
Nik Sumeiko

Après avoir trouvé des réponses, je pense que cette page pourrait être utile . https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation historique de la fusion des déclarations, mais explique pourquoi ce qui suit pourrait fonctionner.

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

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

Pour référence (c'est la bonne réponse):

Dans un fichier de définition .d.ts

type MyGlobalFunctionType = (name: string) => void

Si vous travaillez dans le navigateur, vous ajoutez des membres au contexte de la fenêtre du navigateur en rouvrant l'interface de Windows:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

Même idée pour NodeJS:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}

Maintenant, vous déclarez la variable racine (qui vivra réellement sur window ou global)

declare const myGlobalFunction: MyGlobalFunctionType;

Ensuite, dans un fichier .ts normal, mais importé comme effet secondaire, vous l'implémentez:

global/* or window */.myGlobalFunction = function (name: string) {
  console.log("Hey !", name);
};

Et enfin, utilisez-le ailleurs dans la base de code, avec soit:

global/* or window */.myGlobalFunction("Kevin");

myGlobalFunction("Kevin");
4
Benoit B.

Typescript n'effectue pas de vérification sur les propriétés de chaîne.

window["newProperty"] = customObj;

Idéalement, le scénario de variable globale devrait être évité. Je l'utilise parfois pour déboguer un objet dans la console du navigateur.

3
Irshad

Je voulais utiliser cela dans une bibliothèque Angular (6) aujourd'hui et il m'a fallu un certain temps pour que cela fonctionne comme prévu. 

Pour que ma bibliothèque utilise des déclarations, je devais utiliser l'extension d.ts pour le fichier qui déclare les nouvelles propriétés de l'objet global. 

En fin de compte, le fichier s'est retrouvé avec quelque chose comme:

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

Une fois créé, n'oubliez pas de l'exposer dans votre public_api.ts.

Cela l'a fait pour moi. J'espère que cela t'aides.

2
Dirk

Pour ceux qui souhaitent définir une propriété calculée ou dynamique sur l'objet window, vous constaterez que c'est impossible avec la méthode declare global. Pour clarifier ce cas d'utilisation

window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature

Vous pourriez essayer de faire quelque chose comme ça

declare global {
  interface Window {
    [DyanmicObject.key]: string; // error RIP
  }
}

Ce qui précède sera une erreur cependant. En effet, dans TypeScript, les interfaces ne fonctionnent pas bien avec les propriétés calculées et génèrent une erreur telle que

A computed property name in an interface must directly refer to a built-in symbol

Pour résoudre ce problème, vous pouvez suggérer de convertir window en <any> pour pouvoir le faire.

(window as any)[DynamicObject.key]
2
aug

Créez une interface personnalisée qui étend la fenêtre et ajoutez votre propriété personnalisée comme facultative. 

Ensuite, laissez la fenêtre customWindow qui utilise l'interface personnalisée, mais qui est évaluée avec la fenêtre d'origine. 

Cela a fonctionné avec le [email protected].

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 
2
shuizhongyuemin

Si vous utilisez TypeScript 3.x, vous pourrez peut-être omettre la partie declare global dans les autres réponses et utiliser simplement:

interface Window {
  someValue: string
  another: boolean
}

Cela a fonctionné avec moi lors de l'utilisation de TypeScript 3.3, WebPack et TSLint.

0
Dana Woodman

Tout d'abord, vous devez déclarer l'objet window dans la portée actuelle.
Parce que TypeScript aimerait connaître le type de l'objet.
Comme l’objet window est défini ailleurs, vous ne pouvez pas le redéfinir.
Mais vous pouvez le déclarer comme suit: -

declare var window: any;

Cela ne va pas redéfinir l'objet window ni créer une autre variable avec le nom window.
Cela signifie que la fenêtre est définie ailleurs et que vous ne faites que la référencer dans la portée actuelle.

Ensuite, vous pouvez faire référence à votre objet MyNamespace simplement par: -

window.MyNamespace

Ou vous pouvez définir la nouvelle propriété sur l'objet window simplement en: -

window.MyNamespace = MyObject

Et maintenant, le TypeScript ne va pas se plaindre.

0
Mav55