Cannot declare global variables with TypeScript - javascript

I am in the process of getting rid of most global variables in my program, but some will always be useful.
I have looked up answers to this several times and gave up finding an answer on my own - the supposed way to declare a global var with TS is like so:
declare var x: string;
which would translate to - global.x = 'foo';
but this declaration is not getting rid of the compilations errors or IDE warnings in Webstorm.
What is the best way to declare global vars in my program? I assume the best way to do it would involve a .d.ts file.
Here is the type of warning I see:

Not sure if this is the best way to do it:
in my file in my project called suman.d.ts, I have:
import Global = NodeJS.Global;
interface SumanGlobal extends Global {
_writeTestError: Function,
sumanRuntimeErrors: Array<Error | string>,
sumanOpts: Object,
sumanUncaughtExceptionTriggered: boolean
}
declare var global: SumanGlobal;
seems to work for the moment

Related

Execute top-level JavaScript function inside an arrow function [duplicate]

We have a global object in javascript that we can refer to using window for accessing any global variable. But how to refer to the module scope object where all the variables in that module are stored?
Actually, I need to refer to an imported object in the module using string. If it was a global variable, I could've simply done this,
let object_I_want = window[string];
But for module, I can't find the reference for such object. I also tried using this,
var scope = this;
somefunction(){
let object_I_want = scope[string];
}
But, this is undefined inside module context according to the specification. Is there a way to reference the module scope/module object like window.
I think another way to word your question might be: "How can I access scoped variables using strings?", and the answer is "It's not possible in JavaScript".
If you truly need this kind of dynamic flexibility with your values, you must assign them all to a top-level object (and you must export that object from your module if you want to access it and its values outside the module). Or use eval, if supported in your environment.
There is no such object for modules. The module scope is like a function scope - an environment record that you cannot access from javascript, you can only use it to declare variables.
There is an object that holds all the exported names of a module (which you can get by doing a namespace import * as … from …), but this doesn't seem to be what you want.

Unused Functions Not Recognized In Window

Working in ReactJS, I run into an issue where imported functions that are 'unused' are failing to be recognized by the program and I believe are not being added to the window.
In my case, I'm trying to be able to import functions from other files and then call them by string name.
Ex)
import {myFunction} from '../otherFile';
functionNameString = 'myFunction'
window[functionNameString]() //call function by it's string name
//ERROR: window[functionNameString] is not a function
Without changing my above syntax, I've found two ways I can resolve this:
Add the actual function to the same file as the window[functionNameString]() call
Explicitly assign the function to the window at the top of my file like window.myFunction = myFunction
I'm trying to avoid the first case to keep this file shorter, but also don't understand why I need to do the explicit assignment of the function to the window as shown in the second case (and why defining the function in the same file doesn't need this)
Overall, my question is how can I avoid this explicit assignment of and have these imported functions callable from import (or in a shorter syntax)? Assigning like so is fine for a function or two, but I'm looking at importing 15 funcs from this other file which makes things messy working in this fashion. Thanks!
Modules have their own scope, they aren't at global scope, and imports are created as bindings within the module scope, not globals. That's at least half the point of modules: to not make everything global anymore.
Overall, my question is how can I avoid this explicit assignment of and have these imported functions callable?
They are callable. myFunction() will call your function in your example code. There's no reason whatsoever for window to be involved.
If you need to refer to them by a name in a string for some reason, you can put them in an object:
const functions = {
myFunction,
// ...
};
Then functions[functionNameString]() will work.

Check if variable is defined in Typescript?

I'm trying to check if a variable is undefined using typescript but am not having any luck.
I am currently trying
if (typeof variablename !== 'undefined') { /*do something here*/ }
but for some reason the compiler always gives me the error
Cannot find name 'variablename'
I can pull up the browser console and paste the above code and it works as expected. The file containing the undefined check exists in a file that is not imported by any other JS/TS file.
The TypeScript compiler won't let you access a variable it doesn't know about, since most of the time such accesses are errors.
If you want the compiler to believe that such a variable is in scope, you could declare it first:
declare var variablename: string | undefined;
if (typeof variablename !== 'undefined') { /*do something here*/ }
That doesn't change the emitted JavaScript at all. It just tells the compiler to act as if there is a var named variablename in scope whose type is string | undefined (in your use case it might be some type other than string but I needed an example). In other words, it assumes that your JavaScript will run in a context where variablename of such a type is around.
This isn't exactly what you want, since it's possible at runtime that there is no such variable. Unfortunately there's no way to tell the compiler that the variable might be in scope and that typeof can be used to check it. Variables are either in scope (and you can access them) or they're not (and you can't). There was a proposal at microsoft/TypeScript#23602 to have a way to conditionally declare variables, but nothing came of it. Declaring the variable as definitely-existing but of a type with | undefined in it is as close as you can get, I think.
Playground link to code

Javascript calling a function from another javascript file

File 1
var M = function (speech) {
"use strict";
document.getElementById("speech").innerHTML = speech.toString();
};
File 2
$("#test").click(function () {
M("hello");
});
JS lint probelms v
http://puu.sh/j8AOo/a24a88825b.png
'M' was used before it was defined.
This error is because you're defining M as a global variable in one file, and attempting to invoke it in another. Because global variables are often a sign of code-smell, JSLint makes you specifically declare them. There are a few options to do this. For one, you could prepend File 2 with /*global M*/, and it should stop complaining.
Missing 'new'.
This is based on variable conventions. In JavaScript, we typically only name constructor functions using CamelCase. Because constructor functions are intended to be called with the new keyword, it's detecting this as an error. In this case, your best option is probably to just rename M to m.
For more information on configuration and other JSLint help topics, see this page. Alternatively, if you have any say at all in the matter, I would strongly suggest checking out JSHint instead.

How to preserve global variables in javascript when using Closure compiler with advanced optimization?

I have my own Javascript library, which I want to minify by using Google closure compiler with Advanced optimization. By looking at the docs I see how to declare functions which are used outside of the library.
However I couldn't find a way how to preserve global variables declared in my library. Closure compiler just removes them, because it thinks they are never used. Anybody can help ?
Edit: example code:
var variable_1 = true;
This is defined globally right at the beginning of my library, but it's never used in the library itself. It is used outside the library when it is included in some page. But that Closure compiler doesn't know and thats the reason it removes these declarations.
The closure compiler cannot remove global variables declared as window["variable_1"] = true
I recommend you write to window directly for global variables and I also recommend you use string literals for your variable names so that closure doesn't minify it.
Although you can refer to a "true" global variable through replacing all usage of that global variable with window["varname"], it is usually not a good idea to "pollute" the global namespace. The Closure Compiler is designed to discourage you from doing this.
CAVEAT: window["varname"] and var varname are not the same, as "window" may not always be the global object in non-browser environments. As a matter of fact, the Closure Compiler assumes that the global object and "window" are different. For example, window["varname"] will compile to window.varname instead of var varname. They are NOT the same, although in a browser they work similarly.
It is best to make a global namespace object, then only export that one object. All your "global" variables should become properties under this global namespace variable. Benefits:
All those global variables are renamed to shorter versions
Inlining of constants can happen
The Closure Compiler automatically "flattens" the namespace anyway, so your code won't be any slower
Superior obfuscation
Your code also works in non-browser environments. Remember, "window" may not always exists (e.g. in server-side code) and the "global object" may not always be "window"
If you have global variables that the user must read/set to use your library, it is also discouraged. It is better to expose an API on the global namespace object, then expose the public API's as usual through the window object: window["myLib"]["setConfig"] = myLib.setConfig.
In your case, if you have global variables used in other parts of your non-Closure-Compiled code, you have to consider:
Is it better to put the declaration of those variables outside of the file being compiled by Closure
Why are you not putting the declaration of those variables together with the code using them
Should you actually be Closure-compiling all the code instead of only a portion (it is possible? Do you use another library?)
I've just come across this, and I have my own solution.
Create you're entire library within a self-executing function, putting all the object properties as strings (at least once for each property) like so:
(function () {
var myLibrary = {
'myMethod' : function () {
...
}
}
myLibrary.myMethod['propertyOfTheMethod'] = '';
}());
The usual way to make this accessible from the outside would be to put var myLibrary = before the function and return myLibrary at the end of it so that it gets assigned to a global variable. But the function is executed in the global scope (because it's self-executing), so we can create a property of this using a string literal. So in full:
(function () {
var myLibrary = {
'myMethod' : function () {
...
}
}
myLibrary.myMethod['propertyOfTheMethod'] = '';
this['myLibrary'] = myLibrary;
}());
But, this won't work under "use strict";. The best way to get the global variable in strict mode is with var global = Function('return this')(); then assign your variable to that.

Categories