There are a lot of discussions about how and when to use static classes and how to achieve a real static class in typescript. But I have not found any explanation about the differences between a class with only static members paired with an unuseable constructor and a namespace/module.
How do them both affect the global namespace and what is the difference for the memory and usage?
Because in my opinion and what the official documentation says, it would be more easy to achieve the functionality of a static class by using a namespace construct. It is less code and more easy then to use a real class.
You can always look at the compiled javascript output to see the difference. A namespace is an object that will be merged with other namespaces with the same name.
namespace A{
export function b(){
}
}
javascript output:
var A;
(function (A) {
function b() {
}
A.b = b;
})(A || (A = {}));
A class is a function and a static member is a property of the function.
class A{
public static b(){
}
}
javascript output:
var A = /** #class */ (function () {
function A() {
}
A.b = function () {
};
return A;
}());
Both, namespace and class, will occupy the same name "A" in the global namespace. From the perspecive of a client, there is no difference in accessing a static class member or a function inside a namespace:
A.b();
Personally, I don't use static class members or namespaces, i always define functions and variables at the top level inside a module, and use different modules to group different functions.
The typescript homepage has a good topic about this: https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html
excuse my English
I am presenting an extension on phpbb, but this has been rejected for this.
Line 25: please declare this property in your class or use a local variable.
I can not figure out what to do
They would like you to declare the properties before using them like this:
class banner_scroll_module
{
public $u_action;
private $table;
function main($id, $mode)
{
...
$this->table = $table_prefix . 'banner';
}
}
Or, if they will only be used within that function you can just use local variables:
class banner_scroll_module
{
public $u_action;
function main($id, $mode)
{
...
$table = $table_prefix . 'banner';
}
}
Note that they will also want you to fix $tpl_name and $page_title
In response to your second question (which shouldn't be asked in an answer I believe) you need to free the result like this:
$this->$db->sql_freeresult($result_banner);
In TypeScript I can define a global/top-level namespace and use it in another file like so:
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
And in another file, this works:
foo.blah.baz();
However, if I then import something from another module:
import Thing from 'boo';
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
Suddenly my whole file is a module, the foo.blah namespace is local, not global, and the foo.blah.baz() call in the other file fails. export namespace ... just causes the namespace to become part of the module's export, not a global.
Is there a way to write a TypeScript file which imports from other modules but also defines global/top-level symbols?
At the moment I'm doing this:
import Thing from 'boo';
import * as $ from 'jquery';
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
$.extend(true, window, {foo});
Which works, but the TypeScript compiler still can't see that foo.blah... exists as a global in other files.
(The file is the entry point for Webpack, and I'm trying to import things from other modules in the Webpack bundle and assign them to globals so they can be used in <script> tags on the page.)
When you add the import, you switch from internal modules to external ones, as the spec says:
In external modules, relationships between files are specified in
terms of imports and exports at the file level. In TypeScript, any
file containing a top-level import or export is considered an external
module.
http://www.typescriptlang.org/Handbook#modules-going-external
The philosophy behind external modules is to avoid global objects, why don't you create a new module with foo.blah (and all the stuff you need) and import it as TypeScript expects it?
The solution is to declare namespace in global.
declare global {
namespace foo.blah {
function baz() {
console.log('hello');
}
}
}
create a global.d.ts and put your type there
reference: cannot use d.ts file to load declaration merging
For me, the problem was to call the google-one-tap library from a module. The library is only available as script, but a types package exists: #types/google-one-tap.
Code snippet from the types package #types/google-one-tap/index.d.ts:
export as namespace google;
export const accounts: accounts;
export interface accounts {
id: {
initialize: (idConfiguration: IdConfiguration) => void;
disableAutoSelect: () => void;
[...]
As you can see in the above declarations file, there is a namespace google that contains objects/interfaces.
My code calling the library from a module:
google.accounts.id.initialize(...)
Without the fix (see below) the above code returns an exception when building: error TS2686: 'google' refers to a UMD global, but the current file is a module. Consider adding an import instead.
To be able to see the types and to get successful compilation, I declared a variable for the namespace google as follows. There is no code generated for declarations.
declare var google: {
accounts: google.accounts
};
// Now this works without errors.
google.accounts.id.initialize(...)
All of this is actually not recommended and red flags per documentation. Moreover it says that:
Multiple files that have the same export namespace Foo { at top-level (don’t think that these are going to combine into one Foo!)
That being said, I also had to preserve namespaced construct when migrating to ES6 modules because some systems don't offer a simple way to suddenly change namespace references like find & replace (MS Power Apps for example) or maybe you are really developing a library and want to preserve the entry point foo
If you had different first part of namespace per file, this would be enought:
(window as any).foo = foo
But having multiple, each file would overwrite previous window.foo
But there are ways what you can do when migrating to modules. With some webpack configuration, namespaces CAN be exposed as a public variables.
/*
Merge foonamespace between multiple files and expose it as a global variable. Otherwise foo namespace stays as module scoped variable.
exports global variable foo (because library.name is foo), and it uses a construct that:
- Copy the return value to a target object if it exists, otherwise create the target object first: Basically copies foo.* to foo object. This turns out to be a merge of namespaces.
- Namespace MUST BE exported.
- export: 'foo' means that instead of having global variable foo.foo.blah I have foo.blah (basically this should be the value whatever namespace starts with)
*/
output: {
...
library: {
name: 'foo', //or [name] if you have namespace same as entry point name
type: 'assign-properties' //or var or window if same namespace doesn't span multiple modules
export: 'foo'
},
}
There are many more ways to expose stuff to global scope (different type values available). Refer to webpack documentation
P.S. A module (having import or export statement) means variables get scoped as a module (rightly so) and that brings these challenges in the first place to preserve namespaced construct. Reference
Modules are executed within their own scope, not in the global scope; this means that variables, functions, classes, etc. declared in a module are not visible outside the module
P.S.2 How does webpack achieve it? The output looks something like:
var __webpack_export_target__ = (foo = typeof foo === "undefined" ? {} : foo);
var __webpack_exports_export__ = __webpack_exports__.foo;
for(var i in __webpack_exports_export__) __webpack_export_target__[i] = __webpack_exports_export__[i];
if(__webpack_exports_export__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
Implication is second level namespace must be unique.
I have a plugin that I'm creating and it has a parameter like so:
/**
* Global variable as maven plugin parameter
* #parameter expression="${plugin.var}" default-value=OtherClass.GLOBAL_VAR
*/
private int var;
I have another class called OtherClass that has a public final static int GLOBAL_VAR;.
How would I be able to set the default-value from a variable from the actual plugin software?
You can just omit the declaration of a default value and assign OtherClass.GLOBAL_VAR directly to var:
/**
* Global variable as maven plugin parameter
* #parameter expression="${plugin.var}"
*/
private int var = OtherClass.GLOBAL_VAR;
As long as ${plugin.var} is not defined, var will not change its value.
All variables seem to be global in my groovy scripts I run on groovy script engine. I made some groovy class but when I make variables, they can be accessed from everywhere. for exaple.
class test{
void func1{ a=4 }
void func2{ print(a) }
}
When I invoke this class function func1 from scala then invoke func2, it results "4". Weird thing is if I declare variables like "def a=0" in the function, the scope of the variable will be limited with in the function.
I'm loading my groovy scripts from GroovyScriptEngine like this(using scala)
var gse = new GroovyScriptEngine(pathList.toArray)
var scriptClass = gse.loadScriptByName(file.getName())
var i = scriptClass.newInstance().asInstanceOf[GroovyObject]
then using invokeMethod to invoke functions in the groove script class. Is there anyway to make variable scopes limited with in functions by default?
That's the expected behaviour, described in Scoping and the Semantics of "def".
Using an undeclared variable in a Groovy script creates a binding variable. Binding variables are global to your script. If you declare your variable with def, it become function local.
This behavior only applies because you load your code as a script. I don't believe its possible to change it. Just use a declaration (def or a type) when you need a local variable.
Note that you can also define a binding variable (global) by using the #Field annotation:
class test {
void func1{ #Field int a=4 }
void func2{ print(a) }
}
is equivalent to
class test {
void func1{ a=4 }
void func2{ print(a) }
}