I've been using Google's Closure Compiler for most of my projects, and a few of them in advanced mode with 100% typed.
One of my projects though no longer gets stated as 100% typed and I get warnings for things that I didn't used to get them for, and I can't seem to be able to figure out why. This is the message I get
WARNING - could not determine the type of this expression
v['children'].map(v => new _ChildLineItem(v['child'], v['option'], v['quantity'], v['price'])))))),
^
There's 42 more warnings like it, all about the same code, which I have here
/**
* #constructor
* #param {Array<!_Quote>} quotes
* #param {string} email
* #param {?string} quoteid
*/
function _GetQuotes(quotes, email, quoteid) {
this.quotes = quotes;
this.email = email;
this.quoteid = quoteid;
}
/**
* #constructor
* #param {string} quoteid
* #param {boolean} shipping
* #param {Array<!_Proof>} proofs
* #param {Array<!_LineItem>} lineitems
*/
function _Quote(quoteid, shipping, proofs, lineitems) {
this.quoteid = quoteid;
this.shipping = shipping;
this.proofs = proofs;
this.lineitems = lineitems;
}
/**
* #constructor
* #param {string} number
* #param {string} main
* #param {string} thumbnail
*/
function _Proof(number, main, thumbnail) {
this.number = number;
this.main = main;
this.thumbnail = thumbnail;
}
/**
* #constructor
* #param {string} name
* #param {number} quantity
* #param {number} price
* #param {Array<!_ChildLineItem>} children
* */
function _LineItem(name, quantity, price, children) {
this.name = name;
this.quantity = quantity;
this.price = price;
this.children = children;
}
/**
* #constructor
* #param {string} child
* #param {string} option
* #param {number} quantity
* #param {number} price
* */
function _ChildLineItem(child, option, quantity, price) {
this.child = child;
this.option = option;
this.quantity = quantity;
this.price = price;
}
Ajax({
url: '/ajax/getquotes',
data: Data,
success: function (/** !_GetQuotes */ data) {
var d = new _GetQuotes(
data['quotes'].map(v => new _Quote(v['quoteid'], v['shipping'],
v['proofs'].map(v => new _Proof(v['number'], v['main'], v['thumbnail'])),
v['lineitems'].map(v => new _LineItem(v['name'], v['quantity'], v['price'],
v['children'].map(v => new _ChildLineItem(v['child'], v['option'], v['quantity'], v['price'])))))),
data['email'], data['quoteid']);
...
I can rewrite the closures to specify the types of the objects coming through like this
v['children'].map(function( /** !_ChildLineItem */ v) { new _ChildLineItem(v['child'], v['option'], v['quantity'], v['price'])}
But shouldn't it be able to figure that out from the constructor definitions?
Actually me specifying all of them like this isn't even working
var d = new _GetQuotes(
data['quotes'].map((/** !_Quote */ v) => new _Quote(v['quoteid'], v['shipping'],
v['proofs'].map((/** !_Proof */ v) => new _Proof(v['number'], v['main'], v['thumbnail'])),
v['lineitems'].map((/** !_LineItem */ v) => new _LineItem(v['name'], v['quantity'], v['price'],
v['children'].map((/** !_ChildLineItem */ v) => new _ChildLineItem(v['child'], v['option'], v['quantity'], v['price'])))))),
data['email'], data['quoteid']);
With this warning
WARNING - could not determine the type of this expression
v['children'].map((/** !_ChildLineItem */ v) => new _ChildLineItem(v['child'], v['option'], v['quantity'], v['price'])))))),
^^^^^^^^^^^^^^^^^
The problem you are facing is that the compiler generally treats computed and dot property accesses differently. Computed property accesses are treated as the 'unknown' type unless you give a type signature the [] operator (i.e. the class implements IArrayLike as Array does or IObject[2] for map like objects).
Although, the compiler could understand that x.foo and x['foo'] are reference the same property, it does not currently do this.
[1] https://github.com/google/closure-compiler/wiki/Special-types-in-the-Closure-Type-System
Is there a way to add own helpers to the console HelperSet in Symfony3?
I didn't find any helpful thing in the documentation.
Ok i followed the code and find a simple solution. :)
I just have to add my class that implements the HelperInterface, or extend the abstract Helper class.
$this->getHelperSet()->set(new MyHelper(), 'myhelper');
And myhelper class looks like that:
<?php
namespace MyApp\Helper;
use Symfony\Component\Console\Helper\Helper;
class MyHelper extends Helper
{
/**
* #param $string
* #return string
*/
public function doIt($string) {
return 'this is your '.$string;
}
/**
* Returns the canonical name of this helper.
*
* #return string The canonical name
*/
public function getName() {
return 'myhelper';
}
}
And in my code i can use it like:
$myhelper = $this->helperSet->get('myhelper');
$myString = $myhelper->doIt('hallo');
:)
I've this situation
public class MyTest extends .... {
function providerA(){
return array(array("a"));
}
function providerB(){
return array(array("b"));
}
/**
* #dataProvider providerA
*/
function testOne($a){
$c = "something";
return $c;
}
/**
* #depends testOne
* #dataProvider providerB
*/
function testTwo($b,$c){
var_dump($b);
var_dump($c);
}
}
var_dump($c) -> is always null, why?
I cannot figure out what is happened. On the pdf of phpunit I found this sentence:
"When a test depends on a test that uses data providers, the depending test will be executed
when the test it depends upon is successful for at least one data set. The result of a test that
uses data providers cannot be injected into a depending test."
How can achieve my goal or a result that work in the same way?
I'd suggest to make a static property, which will be filled with data from the testOne. Because of the #depends annotation, testTwo will not run if testOne fails. testOne will add value to the static property c which will be used in the testTwo test.
However, I think better practice is to separate both tests. Thus, the data needed for testTwo will all provided by providerB (not depended on other test).
private static $c = array(array("c"));
function providerA() {
return array(array("a"));
}
/**
* #dataProvider providerA
*/
function testOne($a) {
$c = "something";
self::$c[0][] = $c;
$this->assertTrue(true);
}
/**
* #depends testOne
*/
function testTwo() {
var_dump(self::$c);
}
I am preparing externs for PIXI.js library. I am getting the following warning:
js/Test.js:188: WARNING - Property position never defined on PIXI.Sprite
button.position.y = y;
Here are the relevant extern definitions:
//UPDATE
/**
* #constructor
* #extends {PIXI.Container}
* #param {PIXI.Texture} texture
*/
PIXI.Sprite = function(texture){};
/**
* #constructor
* #extends {PIXI.DisplayObject}
*/
PIXI.Container = function(){};
/**
* #constructor
* #extends {PIXI.EventEmitter}
*/
PIXI.DisplayObject = function(){};
/**
* #type {PIXI.Point}
*/
PIXI.DisplayObject.position;
Still getting the same warning.
What am I doing wrong?
When I am replacing PIXI.DisplayObject.position; with PIXI.DisplayObject.prototype.position; that seems to clear the warning.
Does it mean that I should always define SomeObject.prototype.prop rather then SomeObject.prop ?
This is highlighting the difference between static and prototype properties.
Given:
/**
* #constructor
* #param {number=} opt_num
*/
function foo(opt_num) {
if (opt_num !== undefined) {
this.bar = opt_num;
}
}
foo.prototype.bar = 17;
foo.bar = 42;
We have both a static property and a prototype property of the same name. However they are referenced differently:
console.log((new foo()).bar); // 17
console.log((new foo(0)).bar); // 0
console.log(foo.bar); // 42
So in an extern, when you are defining properties on a type - you typically want to define them on the prototype object:
/** #param {foo} obj_foo */
function log(obj_foo) {
// This is an instance of "foo".
// The "bar" property references prototype or instance
// properties - not static properties.
console.log(obj_foo.bar);
// Static properties can only be referenced by the full namespace
console.log(foo.bar);
}
is there a more elegant way to define optional parameters in annotated routes then to define 2 annotations?
Here's how I did it:
/**
*
* #Route("/view/{lang}/{file}", name="legacy_translation_view_file")
* #Route("/view/{lang}", name="legacy_translation_view")
* #Template()
*/
public function viewAction($lang,$file=null)
{
...
}
i've seen that the annotation class has a field named "defaults" but am not quiet sure about the syntax
thx
Symfony has a page on #Route:
E.g maybe you can try.
/**
* #Route("/{id}/{lang}/{file}", requirements={"id" = "\d+"}, defaults={"file" = null})
*/
public function showAction($id, $lang, $file)
{
}
If null doesn't work try an empty string.