I have a structure which is typed as follows:
/** @type {!Array<{
* cmd: string,
* params: !Array<{name: string}>,
* do: function(!Object, !Array<!Roll20Object>, !Array<string>, boolean):string
* }>} */
One of the values loaded into the structure includes the following field:
do: ((p,t,r,a) => {
/** @type {!Array<string|number|boolean>} */
let results = _.map(t, x => getTokenAttr(x,p.property));
GetTokenAttr's return type is {null|string|number}
. _.map
is typed as follows in the externs for underscore.js:
/**
* Object-style annotation
* @param {Object|Array} obj
* @param {Function} iterator
* @param {Object=} opt_context
* @return {!Array|_}
*/
Closure gives the following error compiling the structure:
pf2utils.js:1029: WARNING - [JSC_TYPE_MISMATCH] initializing variable
found : (Array|_|null)
required: Array<(boolean|number|string)>
let results = _.map(t, x => getTokenAttr(x,p.property));
It seems to be claiming that results
has the possibility of being null
, but it is not clear where this is coming from. The do
declaration promises that the t
parameter is not null (as it's !Array<..>
and the extern for _.map
promises it does not return null (because of @return {!Array|_}
). But Closure is treating _.map
s return as (Array|_|null}
instead, unprompted.
How can I tell Closure that this is a valid assignment and should be null free?
As _
is declared as a class (with @constructor), it is nullable by default, the type _
is equivalent to !_|null
. The return type for map should be, if it can not return null, would be !Array|!_
not !Array|_
.
You can verify the different in the Closure compiler "debugger" playground with this snippet, where the assignment to x
is allowed but the assignment to y
is rejected:
/** @constructor */
function _() {}
/** @type {!Array|_} */
let x = null; // valid
/** @type {!Array|!_} */
let y = null; // type error