Как написать явную аннотацию возвращаемого типа для рекурсивного замыкания с использованием JSDoc - PullRequest
1 голос
/ 09 июня 2019

У меня довольно сложный вариант использования в проекте, который использует vanilla JS и проверяет типы, используя tsc с аннотациями типов, написанными в комментариях JSDoc.У меня есть функция, которая возвращает функцию, и возвращаемая функция может рекурсивно вызывать себя, а также переназначать некоторые переменные замыкания.

Вот глупый пример, который передает точку и выдает ту же ошибку:

/**
 * @returns {function(): number}
 */
function circular() {
  let num = Math.random();

  return function tryAgain() {
    if (num < 0.5) {
      return num;
    }

    num = Math.random();
    return tryAgain();
  };
}

Итак, если я запускаю проверку типов для этого кода, используя tsc:

tsc --allowJs --checkJs --noEmit --strict --target ES2017 *.js

, я получаю следующую ошибку:

error TS7023: 'tryAgain' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

Для начала,эта ошибка кажется довольно ошибочной.У меня явно есть явная аннотация возвращаемого типа, которая является решением, предложенным для похожих циклических ссылок с использованием правильного TypeScript, а не JSDoc.

Но я был бы рад любому обходному решению, которое получит этокомпилировать без массивного рефакторинга, который удаляет замыкания и / или рекурсию.Я уже попробовал несколько возможных обходных путей, ни один из которых не сработал.

Оборачивание функции возврата аннотацией:

  return /** @type {function(): number} */ (function tryAgain() {
    . . .
  });

Обтекание рекурсивного вызова аннотацией:

    return /** @type {number} */ (tryAgain());

Завершение рекурсивного вызова с помощью принуждения:

    return Number(tryAgain());

На данный момент я полностью озадачен тем, как правильно аннотировать это, или, по крайней мере, как заставить проклятую вещь скомпилироваться.

1 Ответ

1 голос
/ 09 июня 2019

Отделение определения функции от return позволяет вам аннотировать tryAgain, что избавляет от ошибки:

/**
 * @returns {function(): number}
 */
function circular() {
  let num = Math.random();

  /**
   * @returns {number}
   */
  function tryAgain() {
    if (num < 0.5) {
      return num;
    }

    num = Math.random();
    return tryAgain();
  }

  return tryAgain;
}

Делая это inline также работает:

/**
 * @returns {function(): number}
 */
function circular() {
  let num = Math.random();

  return /** @returns {number} */ function tryAgain() {
    if (num < 0.5) {
      return num;
    }

    num = Math.random();
    return tryAgain();
  };
};
...