4

I like to define a globally available helper

global.p = console.log.bind(console)

So I can use p('some message') instead of console.log('some message').

But TypeScript complains that p is undefined. Is there a way to tell the TypeScript compiler that there's a global variable p that's available in every file?

Alex Craft
  • 13,598
  • 11
  • 69
  • 133
  • What's the downside of importing the `p` function from a certain file? Why must it be global? – k0pernikus Dec 13 '17 at 13:39
  • Related question: https://stackoverflow.com/questions/45647204/typescript-how-to-use-utilities-file-project-wide-with-minimum-ceremony – k0pernikus Dec 13 '17 at 13:40
  • Because I have TypeScript linter that catches all unused variables, so you can't just import p and leave it there, it has to be used or deleted. Also, I don't want to put `import { p } from xxx` in every file. – Alex Craft Dec 13 '17 at 14:12
  • 1
    I argue that it is a good thing to only import a function when you use it. You, and other maintainer of your project, will get more headaches with global functions in the long run. It helps maintainability *a lot* that dependencies are imported in a certain way. – k0pernikus Dec 13 '17 at 14:17
  • What's good or bad depends on the project. Building skyscraper and hut requires different technic. In my case I care most about the dev speed and want to prototype quickly. So, in my case implicit global variable is much better. – Alex Craft Dec 13 '17 at 14:19
  • You'll get more of a productivity boost by using a proper IDE or editor. WebStorm for example can automatically add your import on the fly through the TypeScript plugin. – k0pernikus Dec 13 '17 at 14:22
  • I think this is good example of a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem): You ask about how to implement your attempted solution, rather than dealing with underlying issue that you find it tedious to add the imports manually. – k0pernikus Dec 13 '17 at 14:24
  • Example - mocha.js in TypeScript Types declares couple of variables as global, like `declare`, `it`, `before`, `after` etc. Is this wrong? Maybe it's wrong, but I want it to be that way. I don't want to put tons of imports in my files. – Alex Craft Dec 13 '17 at 14:48
  • Possible duplicate: https://stackoverflow.com/questions/47736473/how-to-define-global-function-in-typescript – k0pernikus Dec 14 '17 at 11:52

4 Answers4

6

I think I know what you're trying to do — you want typescript to understand that the p variable is set in the global scope without having to import { p } from ... in every file.

If I'm not mistaken, what you need to do is make an ambient declaration:

declare const p: (message: string) => void // or whatever

This doesn't have to be declared in every file. Put it in a d.ts file in a folder called typings/ and then include that file in your tsconfig:

"include": [
    "typings/**/*",
    ...
],

Note: your d.ts file can't import any other modules. But it can use other ambient types that were declared in other d.ts files, without importing them. If you import something, then typescript will not treat your file as an ambient declaration and it won't work.

Matthias
  • 13,607
  • 9
  • 44
  • 60
  • I made this a community wiki answer. If there are any errors in what I've written, please correct it with references. This was all off the top of my head and might not be 100% accurate. But it's a point in the right direction. – Matthias Jan 12 '19 at 05:15
  • It seems to be not correct. You can check out [here](https://stackoverflow.com/questions/45099605/ambient-declaration-with-an-imported-type-in-typescript) for more details. – liuliang Nov 14 '22 at 09:24
2

Smart move to abstract the logging so you don't end up with code throughout your program that depends directly on console.log.

You could declare it as it already exists globally:

declare var p: (message: any, ...additionals: any[]) => void;

But if you had to place this in every file, you might as well:

import { p } from './logging';

By making a logging module with your console.log wrapper.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 4
    Sorry I didn't get it. Adding this line `import { p } from './logging';` is exactly what I'm trying to avoid. I don't want to put it in every file. – Alex Craft Dec 13 '17 at 14:14
  • 2
    @AlexeyPetrushin Why do you want to avoid that? That's exactly what typescript wants to enforce: making your dependencies aka `imports` as explicit as possible so you know what you are using and where it comes from. Globals just muddy the water. – k0pernikus Dec 13 '17 at 14:18
  • How do we avoid putting the `declare` in every file AND also not use imports? – trusktr May 13 '19 at 06:00
0

import {Injectable} from '@angular/core';

@Injectable()
export class GlobalStatus {
  private _status : any;
  constructor() {
    this._status = {
      "GlobaConfigVersion": "0.0.0"
    }
  }
  
  getStatusValue(valKey: string): any {
    return this._status[valKey];
  }
  setStatusValue(valKey: string, theStatus: any): any {
    this._status[valKey] = theStatus;
  }
}

this is the service that i use for global config. Then i can set/get global variables in this way:

import { GlobalStatus } from './globalStatus.service';

//setter
this.globalStatus.setStatusValue("yourValue", value)

// getter
this.globalStatus.getStatusValue("yourValue")
Luca Taccagni
  • 1,059
  • 6
  • 23
  • This will indeed allow you to manage global variable, but that's not _actually_ (despite the title) what OP wanted. See Fenton's answer. – msanford Dec 13 '17 at 14:02
  • 1
    yes sorry i've answered to title. However i think this should be the right way to manage global variables. I have to delete this answer? =) – Luca Taccagni Dec 13 '17 at 14:12
  • 1
    Practically, I'm sure over the next months people will find it useful and up-vote it because of the title of the question. I'd leave it personally, others may chime in with another opinion. If you suddenly get a whack of downvotes, you'll know what to do :) – msanford Dec 13 '17 at 14:25
-1

If you simply want to tell TypeScript to be ok with your p variable, you can declare it at the head of your file :

declare var p: any;
Konal
  • 259
  • 1
  • 3
  • 10
  • Why would you declare it as `any` when you can declare the correct interface, `(message: any, ...additionals: any[]) => void`, as suggested in another answer? – msanford Dec 13 '17 at 16:39
  • No it wouldn't work, it will work only in single file. – Alex Craft Dec 14 '17 at 16:18