Google Closure Compiler type annotations for array

2019-07-18 10:33发布

While playing around with Google Closure Compiler, I found a case where I couldn't force the compiler to give a warning for a wrong variable type. I used the following sample:

/** @typedef ({name: string, token: string}) */
var pendingItem;

/** @type (Array.<pendingItem>) */
var pending = [];

// NOTICE: the token is intentionally misspelled as "toke" to cause a warning
var dummyItem = {
  name: 'NameHere',
  toke: 'SomeToken' 
};

// This should cause a warning, because of the 
// type mismatch (toke instead of token)
pending.push(dummyItem);

// Do something useful so that the whole code wouldn't be optimized to 0 bytes
alert(pending.length);

And it compiles perfectly, instead of giving the expected type warning. But if you use:

pending[1] = {
  name: 'Second Name',
  toke: 'Second Token'
}

You get the expected type mismatch warning.

I understand that it's probably because push doesn't have type-checking defined, since it's a built-in function. It would be expected that defining pending as an array of pendingItem would force it, but it doesn't by default.

The question is whether and how is it possible to add type checking to already defined functions such as push, so that it would give a warning in the example above. I also understand that one way to achieve a similar result would be to add /** @type {pendingItem} */ before dummyItem to force the type, but for educational purposes, I would like to know about adding type checking to functions like push (or maybe stricter definition of pending itself).

Also could somebody explain what is the logic behind renaming object properties? If you compile the above example, it wouldn't rename dummyItem's property name, but it would rename token to a.

1条回答
神经病院院长
2楼-- · 2019-07-18 11:06

To force type checking on push, it has to be redefined in code with the correct type. Note that using object literal notation, you have to define the types by using @type instead of @param, because we are assigning the function to a object's parameter, not defining a normal function. In this case it would be the following:

/** @type {function(pendingItem)} */
pending.push = function(item) {
  Array.prototype.push.call(pending, item);
};

Now when trying to compile the following:

// Still an intentionally misspelled "toke"
var dummyItem = {
  name: 'NameHere',
  toke: 'SomeToken' 
};

// First warning
pending.push(dummyItem);

// Second warning
pending[1] = {
  name: 'Second name',
  toke: 'Second Token'
};

Then both will generate a type mismatch warning, like expected.

Thought that it might be useful to somebody in the future.

查看更多
登录 后发表回答