momentjs getting the version number to display on my help about screen - javascript

We want to display the version number from momentjs and several other products. I am new to javascript (actually doing almost everything with TypeScript).
I can see there is a VERSION and a moment.version. But I can't seem to access either of them, the VS TypeScript tells me they are visible.
(function (undefined) {
/************************************
Constants
************************************/
var moment,
VERSION = "2.1.0",
round = Math.round, i,
// internal storage for language config files
languages = {},

If you're using the definition from here, it would appear that the version property was left off from the list of static properties. You can easily extend it by including it either in the original definition, or because interfaces in TypeScript are extensible, you can add the missing property by declaring the interface in one of your files with the version property.
interface MomentStatic {
version: string;
}
Because the moment global variable is defined to be the interface MomentStatic in the definition file:
declare var moment: MomentStatic;
You won't need to do anything other than add the version property as shown above.
Now, you can use:
var ver : string = moment.version; // currently 2.5.1 for example

Related

JSDoc to handle Rhino's importPackage

In Rhino, one can do
importPackage(Packages.foo.bar.xyzzy);
This imports in the current namespace all the members of the Java foo.bar.xyzzy class.
I've already set up Typescript declaration files for that class so I can use
var x = Packages.foo.bar.xyzzy.memberA;
var y = Packages.foo.bar.xyzzy.memberB;
and get completion, type checking etc in VSCode (and the typescript that it uses)
With that importPackage, I can use
var z = memberA;
and it works (at run time) but VSCode complains because it has no idea that importPackage means that the members are imported.
Can I add some JSDoc that will cause VSCode to know that? It's a sort of
import * from Packages.foo.bar.xyzzy
I guess
EDIT:
class xyzzy extends Packages.foo.bar.xyzzy {}
gets me close, but two problems: Rhino doesn't support class (so I need it to be in a JSDoc comment instead) and it means I can do xyzzy.methodY() now, but not just methodY()
My typescript-fu isn't that strong so I'm not really sure how to go about this
I'm afraid, there is no way to do what you want via typescript + jsdoc.
importPackage works like a with statement. It modifies current execution context. TypeScript itself doesn't support types for with. Also, JavaScript doesn't have such conception as import * from "foo" (The correct one import * as foo from "foo").

UglifyJS - Mangle functions but preserve Function.prototype.name

When using UglifyJS, function names are mangled, unless keep_fnames is set to true. For example, the following Typescript code:
class Test {}
console.log(Test.name);
compiled to JS as:
function Test() {}
console.log(Test.name);
will be uglified to:
function t() {}
console.log(t.name);
and output t instead of test to the console.
Is there a way (other than using keep_fnames option) to preserve the name property after uglification ? (I don't want to use keep_fnames:true because it increases the bundle size quite a lot.
Possible solutions I thought of:
Writing a Webpack plugin that hard codes the function name Test.name = 'Test', but this won't work as Function.prototype.name is a read only property;
Using Typescript decorators, metadata and the reflection API, but design:type metadata is not emitted for classes, it's only emitted for properties (which I believe is because Function.prototype.name exists, but I guess they missed this edge case ?).
As it's explained here, Function.prototype.name cannot be relied on in client-side code, because the information on function original name will be destroyed with minification process. Preventing it from being renamed is quick-and-dirty fix.
name is read-only and non-configurable in some browsers, so doing something like
class Test {
static get name() {
return 'Test';
}
}
or
function Test() {}
Object.defineProperty(Test, 'name', { configurable: true, value: 'Test' });
will fix it in most browsers but result in obscure compatibility problems in rest of them (for example, Android 4.x browser).
The proper way to do this is to never rely on name in client-side code for anything but debugging. As for Node.js and Electron, it depends on whether the code needs to be obfuscated.
If string identifier should exist for a class or a function, another static property name can be picked, e.g. id or unsupported yet conventional displayName.
Is there a way (other than using keep_fnames option) to preserve the name property after uglification...
The only mechanism to keep the correct name involves that name being in the output file, so the short answer is no. If you want to use prototype.name you need to leave that name be.
The alternatives would involve either:
Adding an additional property containing the name, which could introduce errors and would still take up space in your file
Finding a tool that will pre-compile all uses of prototype.name with the string value... I'm not aware that one exists but you never know!

Using TypeScript, and Object.assign gives me an error "property 'assign' does not exist on type 'ObjectConstructor'"

I am writing my question again because earlier it made little sense and I wasn't very clear.
I am receiving data from API that looks something like this:
{"photos":[{"id":1,"title":"photo_1_title"}]}
So, in my code, I have a photos variable, and a method called getPhotos()
I am using infinite scroll so when I reach the bottom of the page, I call getPhotos() again.
photos: any;
getPhotos() {
this.photoService.getPhotos()
.subscribe(
photos => this.photos = photos
// here, instead of doing this, I want to add the array of photos I get back to this.photos using Object.assign however it is giving me the said error
)
}
So if the next time I call it, I get back {"photos":[{"id":2,"title":"photo_2_title"}]}, then I am trying to set this.photos to be
{"photos":[{"id":1,"title":"photo_1_title"}, {"id":2,"title":"photo_2_title"}]}
can someone help me with why
jsfiddle.net/ca46hLw9 doesn't work? I thought assign is supposed to merge contents of an object together right?
Object.assign is an ECMAScript2015 feature and does not exist in ECMAScript5 and lower.
You're most likely targeting to compile your Typescript for ECMAScript5 and therefor the Object interface does not have assign defined.
You can either target ECMAScript2015 by changing your TS compiler configuration with
target: 'es6'
or you can extend the ObjectConstructor interface with the method assign
declare interface ObjectConstructor {
assign(...objects: Object[]): Object;
}
(you can add this declaration anywhere, redeclaring an interface extends it instead of overwriting it)
Or you can coerce Object to any and ignore its typing:
(<any>Object).assign( this.photos, photos )
Whichever you choose, keep in mind that if you want this to run on older browsers you need to add a polyfill. Most modern browsers are fairly close to implementing the ES2015 feature set, but they're not 100% there, meaning that some parts of your code will still fail if you rely on ES2015 functionality.
Typescript will not polyfill Object.assign when targetting ES5 or older, that is why you are getting this error. On the other hand, Babel does have polyfills in the form of plugins, which would mean you need to incorporate Babel transpilation into your build pipeline, see: https://babeljs.io/docs/plugins/transform-object-assign/
As a final option you can consider using a library as Lodash or jQuery, which have their own implementation of Object.assign (called extend)
With Typescript 2.1 or higher, you can use Object spread syntax instead.
let obj = { x: 1, y: "string" };
var newObj = {...obj, z: 3, y: 4}; // { x: number, y: number, z: number }
The order of specifying spread operations determines what properties
end up in the resulting object; properties in later spreads “win out”
over previously created properties.
For typescript version 2.0 or higher, just modify the tsconfig.json file so the "lib" section includes "es6":
"lib": [
"es5",
"es6",
"dom",
"es2015.collection"
]

How do let, require, and prototype work together to make objects in javascript?

Specifically, I'm looking at the Adblock javascript codebase. Several parts to this:
1) There's a line in there
let {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses");
I understand that let is used to create block-scoped variables, but what are the brackets doing?
2) A little further down in the code is:
function Matcher()
{
this.clear();
}
exports.Matcher = Matcher;
Matcher.prototype = {
filterByKeyword = null, //...variables
clear: function() {
//sample function, lots more
},
myfunc : function() {
return "blah blah";
}
}
module.exports makes functions and properties inside it available, but is exports.Matcher = Matcher the same thing? I want to create a Matcher object and use the variables & functions inside of it. I tried emulating the style (in a separate js file) via
let {Matcher} = require("matcher");
function testfunc() {
let matcher = new Matcher();
console.log(matcher.myfunc());
}
and then using node in the terminal with node --harmony test.js.
But it throws an UnexpectedToken error at the let {} block. I'm not sure if I'm creating the object correctly or what exactly is going on. Any ideas on how to start unraveling this puzzle?
The first line is a so called destructuring assignment that can be used to conveniently extract data from objects to variables.
The second block is describing a module that exposes the class Matcher. A very good article on module.exports/exports.xxx is this one.
Your code itself looks perfectly fine according to ES2015 specification. However you should take care when using ES2015 features in node.js and carefully read the docs:
let is only working in strict mode
--harmony_destructuring is a in progress feature, therefore you should not rely on it because it may have some bugs. I recommend using some ES2015 compiler like Babel, Traceur or Typescript if you want to make use of ES2015 features
The first is a destructuring assignment. In the second instance exports.Matcher simply defines the object that the module exports to consumers.

Generation of getters and setters in Javascript compatible with Closure Compiler

I'm writing a library that I hope to be compatible with Closure Compiler in Advanced mode. Most objects in the library maintain an internal object of attributes that are frequently part of the API, which leads to my source files being filled with lots and lots of functions like this.
/*
* Get name.
*/
Layer.prototype.getName = function() {
return this.attrs.name;
}
/*
* Set name.
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
I can think of a billion ways to optimize this to declutter my code a bit. One example: KineticJS, as per this related question, does something a bit like this:
Global.addGettersSetters = function(obj, property) {
obj['get'+property] = function() { return this.attrs[property] }
obj['set'+property] = function(val) { this.attrs[property] = val }
}
// Later that day, in our original object, we have:
Global.addGettersSetters(Layer, 'name');
My understanding is that this is a no-no with Closure Compiler--the names won't be shortened and the functions won't be optimized because I'm specifying the properties of Layer as strings.
So, is there a way for me to fully and properly define the interface without cluttering up my code? Something in the Closure Library I've overlooked, perhaps?
An alternative solution: is there a way to do C#-style properties in modern JS? In a way Closure Compiler finds permissible? I have the luxury of targeting Webkit and only Webkit with this library, so stuff that's not yet fully implemented is fine.
If the getters/setters are public anyway, then you need them to not be renamed in the minified js. That means having them use strings for names is fine - they won't be minified but that's what you wanted.
Yes, modern JS has getters/setters.
You cannot dynamically add a function which could then be compiled (and minified/obfuscated) by the Closure Compiler because that dynamic "addGettersSetters" function would only be used at runtime, so the compiler has no knowledge of what it could be creating. The downside of using the compiler is a lot of duplicate pre-compiled code, but the benefit is that the majority of the places where your getters and setters are used will either be minified or just changed to inline references to the variables.
Also, by putting in explicit getters/setters and properly annotating them with JsDoc annotations:
/*
* Set name.
* #param {string} name
*/
Layer.prototype.setName = function(name) {
this.attrs.name = name;
}
you can add some level of type safety to your code to ensure you get a warning during compilation if someone calls "setName(5)".
Otherwise I would follow Chris's suggestion and look into JS getters / setters (other reference here). I have not used these with the closure compiler though so I cannot vouch for them.
Sorry, I don't get the ne8il answer and why it was marked as the correct one.
You can do what you want by just adding .prototype between obj and [ like this:
function addGettersSetters(obj, property) {
// You can also add this if you don't want to declare attrs = {} each time
// if (!("attrs" in obj.prototype)) obj.prototype.attrs = {};
obj.prototype['get'+property] = function() { return this.attrs[property] }
obj.prototype['set'+property] = function(val) { this.attrs[property] = val }
}
And also writing the property name with capital letter. Then you can use it like this:
var Layer = function() { this.attrs = {}; };
// Or just: 'var Layer = function(){};' if you use the line commented above
addGettersSetters(Layer, 'Name');
var layer = new Layer();
layer.setName("John");
alert(layer.getName()); // "John"
Not a complete answer of the original question, just adding some info.
You can see how various JavaScript OOP frameworks handle getters/setters e.g. here: jsPerf.com - JavaScript Object Oriented Libraries Benchmark with getters and setters
is there a way for me to fully and properly define the interface without cluttering up my code?
Tan Nhu (original author of the benchmark) created his own OOP library jsface which is available at: https://github.com/tnhu/jsface
I like it, I use it for exactly this reason
EDIT: how are the getters/setters generator solved in TypeScript is mentioned e.g. in SO article get and set in TypeScript
For more complete list of other frameworks and their way of encoding getters/setters you can check List of languages that compile to JS · jashkenas/coffeescript Wiki · GitHub

Categories

Resources