Закрытие компиляции набирает: обратитесь к функции (заводской метод)

Предположим, у меня есть класс с фабричным методом:

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);
    }
}

Я хочу ввести зависимость Fooфабричный метод в другом классе, например:

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

Проблема: Closure Compiler говорит, что это не соответствует формальному параметру.

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

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

Очевидно, я могу переписать подпись типа и жесткий код в записи, но я действительно хочу сослаться на Foo.create поэтому нет необходимости обновлять всю кодовую базу каждый раз, когда я добавляю новый параметр в объект параметров.

Как я могу сделать это для CC?

2 ответа

Решение

Общая проблема заключается в том, что вам требуется функция, более приемлемая, чем метод Foo.create. Ник Сантос написал хорошее объяснение этого:

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

Использование свободной функции типа "Функция" или "! Функция" будет работать так, как вы надеетесь.

Я использовал это определение, чтобы проверить:

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

f({createFoo: Foo.create});

Пример отладчика CC

Один из способов - написать тип один раз в typedef, а затем обратиться к нему в обоих местах. (Я не пробовал это, но я думаю, что это должно работать)

/** @typedef {function({a: number, b:number}): Foo} */
var FooCreator;

export class Foo {
    ...

    /**
     * @type {FooCreator}
     */
    static create(options) {
        return new Foo(options);
    }
}

/**
 * @param {{
 *   createFoo: FooCreator
 * }} options
 */
Другие вопросы по тегам