I decided I needed something to help me a bit while implementing interfaces. So I added this function to the base.js file in the closure library.
/**
* Throws an error if the contructor does not implement all the methods from
* the interface constructor.
*
* #param {Function} ctor Child class.
* #param {Function} interfaceCtor class.
*/
goog.implements = function (ctor, interfaceCtor) {
if (! (ctor && interfaceCtor))
throw "Constructor not supplied, are you missing a require?";
window.setTimeout(function(){
// Wait until current code block has executed, this is so
// we can declare implements under the constructor, for readability,
// before the methods have been declared.
for (var method in interfaceCtor.prototype) {
if (interfaceCtor.prototype.hasOwnProperty(method)
&& ctor.prototype[method] == undefined) {
throw "Constructor does not implement interface";
}
}
}, 4);
};
Now this function will throw an error if I declare that my class implements a interface but doesn't implement all the interface's methods. This has absolutely no gain from the end user's perspective, it is simply a nice addition to help the developer. Consequently how do I tell the closure compiler to ignore the below line when it sees it?
goog.implements(myClass, fooInterface);
Is is possible?
It depends on what you mean by ignore. Do you want it to compile down to nothing so that it only works in uncompiled code? If so, you can use one of the standard #define values:
goog.implements = function (ctor, interfaceCtor) {
if (!COMPILED) {
...
}
};
or alternately, only when goog.DEBUG is enabled:
goog.implements = function (ctor, interfaceCtor) {
if (goog.DEBUG) {
...
}
};
if these don't fit you can define your own.
Or do you mean something else entirely?
Related
My Python API returns a JSON object, for example:
{
a: 1,
b: 'hi'
}
I also have a class for it in the client:
class Sth {
constructor() {
this.a = null;
this.b = null;
}
}
I receive an object and pass it without modification to a function. Should I use #param like this, instead of a simple #param {*}?
/**
* #param {Sth} sth Is Sth appropriate here?
*/
function f(sth) {
// Do sth
}
Typically interaction with an outside/thirdparty resource is typed by an extern. If you're converting the code locally, that is: fetching and using the data to create an instance then your solution is correct: the class would be enough. If however you're fetching the data and the passing it to a constructor, you'll likely want to define a type in an externs.
When getting started with externs I find the closure debugger incredibly useful.
Yes, that is appropriate. JSDocs will treat the class as a type. If the Sth class isn't available in the same file as your function you'll probably need a JSDoc type definition in that file, e.g. with /** #typedef {import("./path/to/your/class/file.js").Sth} Sth*/
If you can avoid #param {*} you generally should, since having more type information is always better!
I'm trying to use gRPC at React Native.
First, I was able to setup my gRPC module with Objective-C.
Next, I made a native module for that gRPC module.
The gRPC module is quite simple.
rpc CheckEmail(EmailCheckRequest) returns (EmailCheckResponse) {}
message EmailCheckRequest {
string email = 1;
}
message EmailCheckResponse {
common.RetCode ret = 1;
}
As you can see, there is one input parameter(email address) and returns a "Return Code".
I checked how to make a native module at https://facebook.github.io/react-native/docs/native-modules-ios.html and it shows how to make a module with a parameter or a module with a return value, but it does not explain how to make one with both.
Here are the examples.
Module with a parameter
RCT_EXPORT_METHOD(addEvent:(NSString *)name)
{
RCTLogInfo(#"Pretending to create an event %#", name);
}
Module with a return value(Actually, with Promise)
RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *events = ...
if (events) {
resolve(events);
} else {
NSError *error = ...
reject(#"no_events", #"There were no events", error);
}
}
Anyway, based on this, I made my own code like this.
RCT_REMAP_METHOD(checkEmail: (NSString *)email, resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
/* ... */
}
And the react-native side javascript code is like this.
var NetworkService = NativeModules.NetworkService;
var ret = NetworkService.checkEmail('spike#merong.com');
There was no compile error, but while running the app, XCode returns this runtime error at RCT_REMAP_METHOD line
"com.facebook.React.JavaScript (11):EXC_BAD_ACCESS(code=1, address=0x88)
It looks like there is something wrong with RCT_REMAP_METHOD macro, but don't know Objective-C details and don't know how to use marco.
If there is someone who knows how to use RCT_REMAP_METHOD macro to export a module with a parameter and a return value or if there is something wrong with my code, please let me know.
Additional Finding
I followed the definition of RCT_REMAP_METHOD and it seems that it is okay to use RCT_EXPORT_METHOD instead, because EXPORT is redefinition of REMAP and there is an example of Promises with EXPORT, but not sure whether it is the right way to do this.
* ## Promises
*
* Bridge modules can also define methods that are exported to JavaScript as
* methods that return a Promise, and are compatible with JS async functions.
*
* Declare the last two parameters of your native method to be a resolver block
* and a rejecter block. The resolver block must precede the rejecter block.
*
* For example:
*
* RCT_EXPORT_METHOD(doSomethingAsync:(NSString *)aString
* resolver:(RCTPromiseResolveBlock)resolve
* rejecter:(RCTPromiseRejectBlock)reject
* { ... }
*
* Calling `NativeModules.ModuleName.doSomethingAsync(aString)` from
* JavaScript will return a promise that is resolved or rejected when your
* native method implementation calls the respective block.
*
*/
RCT_EXPORT_METHOD is just to remap the js function to native function. This is useful when multiple native methods are the same up to the first colon and would have conflicting JavaScript names.
As the define RCT_REMAP_METHOD(js_name, method), the js_name means the function called from the js code, method means the native function name.
So if you want to export a method with a parameter (or more), you can do like so:
// Bridge.m
RCT_EXPORT_MODULE(Bridge)
RCT_REMAP_METHOD(findEvents,
type:(NSString *)type
params:(NSDictionary *)params
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{ ... }
Then from the js code, call the function like this:
const Bridge = NativeModules.Bridge;
class App extends Component {
asnyc _buttonPress() {
try {
let result = await Bridge.findEvents("type", {"key": "value"});
// handle the result
} catch(e) {
// handle the error
}
}
}
Make sure the RCTPromiseResolveBlock and RCTPromiseRejectBlock are the last two parameters.
As I mentioned at the additional finding part, I was able to export a module with a parameter and a return value with RCT_EXPORT_METHOD.
RCT_EXPORT_METHOD(checkEmail: (NSString *)email
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
/* ... */
}
In this way, I was able to export "checkEmail".
Javascript : NativeModules.ModuleName.checkEmail(email);
I have no Objective-C background knowledge, so even if it works in this way, if there is something wrong with my code, please let me know. =)
Situation: using functions to declare your Classes
If you are using and declaring classes with some custom (or framework function) as WinJs does (check their open source git directory), you are certainly familiar with this kind of code:
function define(constructor, instanceMembers, staticMembers) { }
function derive(baseClass, constructor, instanceMembers, staticMembers) { }
define(function constructor(){
this.yourProperty = 1;
}, {
// Prototype object
somePrototypeFunction: function(){
// When you type "this." here, it will not show up "yourProperty" declared
// in the constructor, because you have not instanciated the class,
// intellisense does not know that everything is linked
}
}
Common problem on these "custom" functions
Intellisense does not show up the values declared within the constructor when you try to reach them from the prototype functions.
I found something that have helped me: http://social.msdn.microsoft.com/forums/windowsapps/en-US/3eee400a-fefd-4f5e-9109-68df03fef006/javascript-intellisense-with-this-inside-gettersetter
This leaded me to the solution that I share to you below, it was a pain to make it work, and actually I was about to ** AGAIN ** let go with that problem which was something really disapointing especially with big team projects.
I find it weird that there are not many complaints about this on the web, maybe it's a configuration problem? However I had that problem on all VSD installations I saw.
So I hope the following solution will help you too if you run into the same situation.
After a few hours I finally have a solution which is not perfect (I have handled .base like in C# in my javascript library, but with the following code I can't say to intellisense that this ".base(...) " exists in the context of the prototype functions and constructor). If you have any tip on how to do that let me know, I'm interested.
Tested on Visual Studio 2013.
Simply change window.define / window.derive to the namespace and name you actually use (for WinJs it would be WinJS.Class.define and WinJS.Class.derive).
Add in _references.js the relative path of the file where you will put the following code, just after your library
And that's all! You'll have intellisense inside your
(function (window) {
"use strict";
/*
* Goal: make intellisense understand that the constructor of your define/derive functions are linked to the prototype object you have supplied.
* Tested on WinJs library and other custom libraries.
* Save this in a file, and reference it only in _references.js, insert it after your library containing the define/derive functions
*/
function initIntellisenseFor(constructor, baseClass) {
var inst = new constructor();
// Force intellisense to run function
for (var key in inst) {
if (typeof inst[key] == 'function') {
try {
inst[key]();
} catch (e) {
// Silent fail if wrong arguments (not sure if needed)
}
}
}
// Force intellisense to discover constructor
inst.constructor = constructor;
// Missing: .base() implementation for each method with redirection to the appropriate parent class method
}
var oldDefine = window.define;
window.define = function (constructor, instanceMembers, staticMembers) {
var result = oldDefine.call(this, constructor, instanceMembers, staticMembers);
initIntellisenseFor(result);
return result;
};
var oldDerive = window.derive;
window.derive = function (baseClass, constructor, instanceMembers, staticMembers) {
var result = oldDerive.call(this, baseClass, constructor, instanceMembers, staticMembers);
initIntellisenseFor(result, baseClass);
return result;
};
})(this);
I'm using a design pattern that uses the return statement to expose public class methods.
Problem is: I'm getting a lot of JSC_INEXISTENT_PROPERTY warnings in Closure Compiler's Advanced mode, which makes it difficult to check the warnings that actually matter.
Example of the pattern I use:
// ==ClosureCompiler==
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
/**
* #constructor
*/
var MyClass = function() {
var someFunc = function(myString) {
console.log(myString);
}
return {
myPublicFunc: someFunc
};
}
var myClassInstance = new MyClass();
myClassInstance.myPublicFunc('Hello World');
Warnings:
JSC_INEXISTENT_PROPERTY: Property myPublicFunc never defined on MyClass \
at line 16 character 0
myClassInstance.myPublicFunc('Hello World');
Output (formatted):
(new function() {
return {
a: function(a) {
console.log(a)
}
}
}).a("Hello World");
Which is weird, because Closure understood what the code was doing and compiled the code correctly, renaming myPublicFunc consistently to a. So why did I get this warning? Am I doing something wrong?
Note: I do not want to turn off these warnings because it would also hide warnings I actually care about. I also do not want to use quoted strings or exports because I do want Closure to compress these.
Your function is annotated incorrectly. It's actually not a constructor and in this case the new keyword is unnecessary. Your function simply returns an anonymous type with a myPublicFunc property.
To annotate such a pattern, you would use the record type:
/** #return {{myPublicFunc: function(string) }} */
var MyClass = function() {
var someFunc = function(myString) {
console.log(myString);
}
return {
myPublicFunc: someFunc
};
};
var myClassInstance = MyClass(); // new keyword not needed
myClassInstance.myPublicFunc('Hello World');
Another annotation option is to create an interface and type-cast the returned object to be that interface. This option would be useful when multiple functions return an object that conforms to the same interface.
You can also use:
/** #type {function(new:{myPublicFunc: function(string)} )} */
var MyClass = function() {...
The function can be called with "new" but doesn't return an instance of "MyClass".
Adding
MyClass.prototype.myPublicFunc = null;
would solve the problem though I don't know whether this is the best solution.
I don't really know how the compiler works, but I could imagine that if you have a constructor function, it expects instance properties to be assigned to this inside the constructor or to MyClass.prototype.
If you remove the #constructor annotation and omit new, then there is not warning (but the compiled code is only console.log("Hello World");.
I recently built a project using the Dojo toolkit and loved how you can mark a section of code to only be included in the compiled version based on an arbitrary conditional check. I used this to export private variables for unit testing or to throw errors vs. logging them. Here's an example of the Dojo format, I'd love to know if there are any special directives like this for the Google Closure Compiler.
window.module = (function(){
//private variable
var bar = {hidden:"secret"};
//>>excludeStart("DEBUG", true);
//export internal variables for unit testing
window.bar = bar;
//>>excludeEnd("DEBUG");
//return privileged methods
return {
foo: function(val){
bar.hidden = val;
}
};
})();
Edit
Closure the definitive guide mentions that you can extend the CommandLineRunner to add your own Checks and Optimizations that might be one way to do it. Plover looks promising as it supports custom-passes.
This simple test case worked. Compile with --define DEBUG=false
/**
* #define {boolean} DEBUG is provided as a convenience so that debugging code
* that should not be included in a production js_binary can be easily stripped
* by specifying --define DEBUG=false to the JSCompiler. For example, most
* toString() methods should be declared inside an "if (DEBUG)" conditional
* because they are generally used for debugging purposes and it is difficult
* for the JSCompiler to statically determine whether they are used.
*/
var DEBUG = true;
window['module'] = (function(){
//private variable
var bar = {hidden:"secret"};
if (DEBUG) {
//export internal variables for unit testing
window['bar'] = bar;
}
//return privileged methods
return {
foo: function(val){
bar.hidden = val;
}
};
})();
console.log(window['bar']);
module.foo("update");
console.log(window['bar']);
Closure Compiler supports "defines", like this:
/** #define {boolean} */
var CHANGABLE_ON_THE_COMMAND_LINE = false;