Crie uma variável global no TypeScript

95

Em JavaScript, posso apenas fazer isso:

 something = 'testing';

E então em outro arquivo:

 if (something === 'testing')

e terá que somethingser definido (desde que tenham sido chamados na ordem correta).

Não consigo descobrir como fazer isso no TypeScript.

Isso é o que eu tentei.

Em um arquivo .d.ts:

interface Window { something: string; }

Então, em meu arquivo main.ts:

 window.something = 'testing';

então em outro arquivo:

 if (window.something  === 'testing')

E isso funciona. Mas eu quero ser capaz de perder window.parte disso e apenas somethingser global. Existe uma maneira de fazer isso no TypeScript?

(Caso alguém esteja interessado, estou realmente tentando configurar meu registro para meu aplicativo. Quero poder chamar log.Debugde qualquer arquivo sem ter que importar e criar objetos.)

Vaccano
fonte
Alternativamente: Não crie globais. Importar é realmente fácil com vscode. Basta digitar o que deseja usar, clicar em tab para importar automaticamente e continuar.
Devin G Rhode

Respostas:

3

Ok, então isso é provavelmente ainda mais feio do que o que você fez, mas de qualquer maneira ...

mas eu faço o mesmo então ...

O que você pode fazer para fazer isso em puro TypeScript é usar a evalfunção da seguinte forma:

declare var something: string;
eval("something = 'testing';")

E mais tarde você poderá fazer

if (something === 'testing')

Isso nada mais é do que um hack para forçar a execução da instrução sem que o TypeScript se recuse a compilar e nós, declare varpara o TypeScript, compilar o resto do código.

tforgione
fonte
Isso não está funcionando para mim. Tenho eval ('myglobalvar = {};') ;. Isso resulta em: Uncaught ReferenceError: myglobalvar não está definido em eval (eval em <anônimo> .....). Curiosamente, se eu executá-lo no console, ele funciona.
Ryan How
2
@DragonRock Tentei Chrome e FF. Então, eu realmente não tenho certeza do que estava acontecendo. De qualquer forma acabei fazendo declare var myglobalvar; (<qualquer> janela) .myglobalvar = {}; Depois, posso referenciá-lo sem janela.
Ryan How
2
Isso realmente deve ser feito com um .d.tsarquivo de definição.
brianespinosa
2
Isso funciona para mim:export declare const SERVER = "10.1.1.26";
xinthose
2
O uso evalé altamente desencorajado, por isso sugiro usar esta solução stackoverflow.com/a/56984504/5506278
Yaroslav Bai
63

Dentro de um .d.tsarquivo de definição

type MyGlobalFunctionType = (name: string) => void

Se você trabalha no navegador, adiciona membros ao contexto da janela do navegador:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

Mesma ideia para NodeJS:

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

Agora você declara a variável raiz (que na verdade viverá na janela ou global)

declare const myGlobalFunction: MyGlobalFunctionType;

Então, em um .tsarquivo normal , mas importado como efeito colateral, você realmente o implementa:

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

E, finalmente, use-o em outro lugar na base de código, com:

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

myGlobalFunction("Kevin");
Benoit B.
fonte
4
(Apenas fazendo um comentário passageiro) Fale sobre muito trabalho para criar uma variável global simples! lol
Pytth
6
@Benoit Não entendi a parte que diz "mas importado como efeito colateral". O que você quer dizer com isso?. Tentei fazer isso, mas não está funcionando para mim. Você poderia compartilhar um exemplo de código-fonte?
BernalCarlos
Isso funciona bem para .tsarquivos, mas quando uso window.myGlobalFunctionem meus .tsxarquivos, não funciona. O que mais eu preciso mudar ?!
Kousha
13
Onde você coloca o arquivo d.ts e como configura o TypeScript para carregá-lo?
Matthias
28

globalThis é o futuro.

Primeiro, os arquivos TypeScript têm dois tipos de scopes

Âmbito global

Se o arquivo não tem qualquer importou exportlinha , este arquivo seria executado no escopo global que todos declaração em que são visíveis fora deste arquivo.

Portanto, criaríamos variáveis ​​globais como esta:

// xx.d.ts
declare var age: number

// or 
// xx.ts
// with or without declare keyword
var age: number

// other.ts
globalThis.age = 18 // no error

Toda a magia vem var. Substitua varpor letou constnão funcionará.

escopo do módulo

Se o seu arquivo tiver qualquer linha importouexport , este arquivo será executado dentro de seu próprio escopo, que precisamos estender globalmente por fusão de declaração .

// xx[.d].ts
declare global {
  var age: number;
}

// other.ts
globalThis.age = 18 // no error

Você pode ver mais sobre o módulo nos documentos oficiais

edvard chen
fonte
Mas como você faria isso sem o hack 'var'? Eu acho que isso significa, como eu faria o aumento de tipo no globalThis?
Tom de
1
@Tom varé necessário. Mas você pode apenas declarar a variável sem inicialização
edvard chen
Funcionou para mim (pelo menos por agora), muito obrigado, eu gostaria que essa resposta subisse FYI: No meu caso, eu precisava adicionar // @ts-ignoreacima da globalThislinha para o linter.
David
Como você chamaria a variável de idade em qualquer arquivo datilografado?
Ashok kumar Ganesan
19

É assim que eu consertei:

Passos:

  1. Declarado um namespace global, por exemplo, custom.d.ts conforme abaixo:
declare global {
    namespace NodeJS {
        interface Global {
            Config: {}
        }
    }
}
export default global;
  1. Mapeie o arquivo criado acima em "tsconfig.json" como abaixo:
"typeRoots": ["src/types/custom.d.ts" ]
  1. Obtenha a variável global criada acima em qualquer um dos arquivos conforme abaixo:
console.log(global.config)

Nota:

  1. versão datilografada: "3.0.1".

  2. No meu caso, o requisito era definir a variável global antes de inicializar o aplicativo e a variável deve acessar todos os objetos dependentes para que possamos obter as propriedades de configuração necessárias.

Espero que isto ajude!

Obrigado

Vikash Kumar Choudhary
fonte
14

Descobri uma maneira que funciona se usar JavaScript combinado com TypeScript.

logging.d.ts:

declare var log: log4javascript.Logger;

declaração de log. js :

log = null;

initalize-app.ts

import './log-declaration.js';

// Call stuff to actually setup log.  
// Similar to this:
log = functionToSetupLog();

Isso o coloca no escopo global e o TypeScript sabe disso. Posso usar em todos os meus arquivos.

NOTA: Acho que isso só funciona porque tenho a allowJsopção TypeScript definida como true.

Se alguém postar uma solução pura do TypeScript, vou aceitar isso.

Vaccano
fonte
1
No seu arquivo initalize-app.ts você pode usar: declare var log: any; Então você não precisa ter o arquivo d.ts ou o arquivo js. Você pode substituir qualquer um por um tipo real ou uma definição de interface também.
Mattferderer
6

estou usando apenas isso

import {globalVar} from "./globals";
declare let window:any;
window.globalVar = globalVar;
Dima V
fonte
1
Isso joga fora todas as informações de tipo. Também pode usar Javascript.
Timmmm
4

Passei algumas horas para descobrir a maneira correta de fazer isso. No meu caso, estou tentando definir a variável "log" global para que as etapas sejam:

1) configure seu tsconfig.jsonpara incluir seus tipos definidos ( src/typespasta, node_modules - você decide):

...other stuff...
"paths": {
  "*": ["node_modules/*", "src/types/*"]
}

2) crie o arquivo src/types/global.d.tscom o seguinte conteúdo ( sem importações! - isso é importante), fique à vontade para mudar anypara atender às suas necessidades + use a windowinterface em vez de NodeJSse estiver trabalhando com o navegador:

/**
 * IMPORTANT - do not use imports in this file!
 * It will break global definition.
 */
declare namespace NodeJS {
    export interface Global {
        log: any;
    }
}

declare var log: any;

3) agora você pode finalmente usar / implementar logonde for necessário:

// in one file
global.log = someCoolLogger();
// in another file
log.info('hello world');
// or if its a variable
global.log = 'INFO'
Alexey
fonte
O que está pathsdentro tsconfig.json? Os documentos não mencionam isso.
também
E por que é Globalcapitalizado nas definições, mas não no uso real?
também
@tambre não tem certeza de por que os documentos do TS não têm isso documentado, você pode encontrar alguns detalhes sobre essa configuração aqui: json.schemastore.org/tsconfig e aqui: basarat.gitbooks.io/typescript/docs/project/tsconfig.html Sobre Globalcom capital - é assim que a declaração de interface "global" é nomeada no namespace nodejs.
Alexey
1

Eu precisava tornar o lodash global para usar um arquivo .js existente que não podia alterar, apenas exigir.

Eu descobri que isso funcionou:

import * as lodash from 'lodash';

(global as any)._ = lodash;
TrueWill
fonte
0

Como um complemento para a resposta de Dima V, isso é o que eu fiz para fazer isso funcionar para mim.

// First declare the window global outside the class

declare let window: any;

// Inside the required class method

let globVarName = window.globVarName;

Jonathan Cardoz
fonte
A pessoa que votou contra isso pode explicar o motivo?
Jonathan Cardoz
7
Bem, esta é uma solução como colocar um pedaço de fita adesiva preta sobre a luz de "verificar o motor" no painel. Ele corrige o problema, mas não da maneira certa. Ele oblitera tipos. Não é uma solução ideal; é uma solução alternativa que também contorna o propósito principal do typescript: ter tipos.
Matthias
0

Isso está funcionando para mim, conforme descrito neste tópico :

declare let something: string;
something = 'foo';
Nacho Coloma
fonte
0

Estou usando este:

interface Window {
    globalthing: any;
}

declare var globalthing: any;
YehudaR
fonte