apscience apscience - 6 months ago 14
Javascript Question

Closure compiler typing: Refer to function (factory method)

Suppose I have a class with a factory method:

export class Foo {
constructor(options) {
this.a = options.a;
this.b = options.b;
}

/**
* @param {{
* a: number,
* b: number
* }} options
* @return {!Foo}
*/
static create(options) {
return new Foo(options);
}
}


I want to dependency inject
Foo
's factory method in another class, like:

/**
* @param {{
* createFoo: !function(!Object): !Foo
* }} options
*/


The problem: Closure Compiler says this does not match the formal parameter.

found : {
createFoo: function ({a: number, b: number): Foo,
}

required: {
createFoo: function (Object): Foo,
}


Obviously I can rewrite the type signature and hard code in the record, but I really want to refer to
Foo.create
so there's no need to update the entire codebase every time I add a new param to the options object.

How can I do this for CC?

Answer

The general problem is that you are requiring a function that is more accepting than the Foo.create method. Nick Santos wrote a good explanation of this:

http://closuretools.blogspot.com/2012/06/subtyping-functions-without-poking-your.html

Using a loose function type "Function" or "!Function" will work as you would hope.

I used this definition to verify:

/** @param {{createFoo: !Function}} options */
function f(options) {}

f({createFoo: Foo.create});

CC debugger sample

Comments