Как указать разрешение и тип отклонения обещания в JSDoc?

84

У меня есть код, который возвращает объект обещания, например, используя библиотеку Q для NodeJS.

var Q = require('q');

/**
 * @returns ???
 */
function task(err) {
    return err? Q.reject(new Error('Some error')) : Q.resolve('Some result');
}

Как задокументировать такое возвращаемое значение с помощью JSDoc?

Арикон
источник
Мне было интересно о чем-то подобном. Как мне задокументировать тип возвращаемого значения функции, которая может возвращать несколько разных значений в зависимости от ввода и состояния приложения?
Hoffmann
Используйте синтаксис подстановочного знака : @returns {*}
Пол Свитт,
Синтаксис подстановочных знаков не так уж специфичен и не помогает.
Арикон
2
@arikon Помогает @returns {ErrorObject|ResultObject}? Использование знака «вертикальная черта» в описании типа является обычной практикой.
Джон Доу
3
@ john-doe Нет, это не так. Потому что функция возвращает объект Promise, а не просто результат или ошибку.
Arikon

Ответы:

77

Даже если они не существуют в Javascript, я обнаружил, что JSdoc понимает «общие типы».

Таким образом, вы можете определить свои собственные типы, а затем использовать /* @return Promise<MyType> */. В результате получится красивый TokenConsume (токен) → {Promise. <Token>} со ссылкой на ваш пользовательский Tokenтип в документе.

/**
 * @typedef Token
 * @property {bool} valid True if the token is valid.
 * @property {string} id The user id bound to the token.
 */

/**
 * Consume a token
 * @param  {string} token [description]
 * @return {Promise<Token>} A promise to the token.
 */
TokenConsume = function (string) {
  // bla bla
}

Он даже работает с /* @return Promise<MyType|Error> */или /* @return Promise<MyType, Error> */.

Jillro
источник
1
@ Себастьян, да, это идея!
jillro
Для YUIDoc я нашел эти работы:@return {Promise|Token}
J Chris A
хорошая идея! я изменил его на:@returns {Promise<ForumPost>|Promise<false>|Error}
Przemek Lewandowski
1
Мне очень не нравится это решение, потому что jsdoc разделяет typedef на другую страницу, чем функция, которая его возвращает. Это также требует, чтобы вы назвали все типы разрешаемых объектов, но все, что вам действительно нужно, - это вернуть несколько значений и заключить их в объект.
Боб МакЭлрат
2
Новости от владельца проекта о текущем решении и о том, что планируется к выпуску github.com/jsdoc3/jsdoc/issues/1197#issuecomment-312948746
Майк Грейс
7

Я обычно определяю внешний тип обещания:

/**
* A promise object provided by the q promise library.
* @external Promise
* @see {@link https://github.com/kriskowal/q/wiki/API-Reference}
*/

Теперь вы можете описать в @returnзаявлении документации вашей функции, что происходит с обещанием:

/**
* @return {external:Promise}  On success the promise will be resolved with 
* "some result".<br>
* On error the promise will be rejected with an {@link Error}.
*/
function task(err) {
    return err? Q.reject(new Error('Some error')) : Q.resolve('Some result');
}
чудо
источник
6

С JSDoc вы также можете создавать собственные типы, используя @typedef. Я использую это довольно часто, поэтому props / params, которые являются строками или массивами, ссылаются на описание типа (например, stringя создал typedef, который включает исходные данные, доступные для строки (см. Пример JSDoc ниже). Вы можете определить настраиваемый тип таким же образом. Это потому, что вы не можете использовать точечную нотацию объекта для возврата, как вы можете для @property для обозначения того, что находится в возврате. Поэтому в случаях, когда вы возвращаете что-то вроде объекта, вы можете создать определение для этого типа (' @typedef MyObject), а затем@returns {myObject} Definition of myObject .

Я бы не сходил с ума от этого, потому что типы должны быть как можно более буквальными, и вы не хотите загрязнять свои типы, но есть случаи, когда вы хотите определить тип явно, и поэтому вы можете задокументировать, что в нем (хорошим примером является Modernizr ... он возвращает объект, но у вас нет на него документации, поэтому создайте собственный typedef, который подробно описывает, что находится в этом возвращении).

Если вам не нужно идти по этому пути, то, как уже упоминалось, вы можете указать несколько типов для любых @param, @property или @return, используя канал |.

В вашем случае, вы должны также документировать , @throwsпотому что вы бросаете new error: * @throws {error} Throws a true new error event when the property err is undefined or not available.

//saved in a file named typedefs.jsdoc, that is in your jsdoc crawl path
/**
    * @typedef string
    * @author me
    * @description A string literal takes form in a sequence of any valid characters. The `string` type is not the same as `string object`.
    * @property {number} length The length of the string
    * @property {number} indexOf The occurence (number of characters in from the start of the string) where a specifc character occurs
    * @property {number} lastIndexOf The last occurence (number of characters in from the end of the string) where a specifc character occurs
    * @property {string|number} charAt Gives the character that occurs in a specific part of the string
    * @property {array} split Allows a string to be split on characters, such as `myString.split(' ')` will split the string into an array on blank spaces
    * @property {string} toLowerCase Transfer a string to be all lower case
    * @property {string} toUpperCase Transfer a string to be all upper case
    * @property {string} substring Used to take a part of a string from a given range, such as `myString.substring(0,5)` will return the first 6 characters
    * @property {string} substr Simialr to `substring`, `substr` uses a starting point, and then the number of characters to continue the range. `mystring.substr(2,8)` will return the characters starting at character 2 and conitnuing on for 8 more characters
    * @example var myString = 'this is my string, there are many like it but this one is HOT!';
    * @example
    //This example uses the string object to create a string...this is almost never needed
    myString = new String('my string');
    myEasierString = 'my string';//exactly the same as what the line above is doing
*/
шторм теней
источник
1
К сожалению, это не работает в PHPStorm, который выделяет тип в @typedefтеге как неразрешенный. Да, да, я даю определение прямо здесь!
Дэвид Харкнесс
Я не выбрасываю Error, просто создаю его экземпляр, чтобы передать его Q.reject ()
Арикон
6

Синтаксис, поддерживаемый в настоящее время Jsdoc3:

/**
 * Retrieve the user's favorite color.
 *
 * @returns {Promise<string>} A promise that contains the user's favorite color
 * when fulfilled.
 */
User.prototype.getFavoriteColor = function() {
     // ...
};

Поддерживается в будущем?

/**
 * A promise for the user's favorite color.
 *
 * @promise FavoriteColorPromise
 * @fulfill {string} The user's favorite color.
 * @reject {TypeError} The user's favorite color is an invalid type.
 * @reject {MissingColorError} The user has not specified a favorite color.
 */

/**
 * Retrieve the user's favorite color.
 *
 * @returns {FavoriteColorPromise} A promise for the user's favorite color.
 */
User.prototype.getFavoriteColor = function() {
    // ...
};

См. Обсуждение github по адресу: https://github.com/jsdoc3/jsdoc/issues/1197

Holmberd
источник
1
Просто нашел то же самое. Ссылка на упомянутый выше комментарий от владельца проекта github.com/jsdoc3/jsdoc/issues/1197#issuecomment-312948746
Майк Грейс
5

Там же еще один способ сделать это , даже если это может быть DEPRECATED . Акцент на мощь, поскольку кто-то говорит, что он устарел (проверьте комментарии к этому ответу), в то время как другие говорят, что любой из них в порядке. Я все равно сообщаю об этом для полноты картины.

Теперь возьмем, Promise.all()например, что возвращает Promise, выполненный с массивом. В стиле точечной записи это будет выглядеть, как показано ниже:

{Promise.<Array.<*>>}

Он работает с продуктами JetBrains (например, PhpStorm, WebStorm), а также используется в документации jsforce. .

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

В любом случае, если вы возьмете следующую функцию в качестве примера:

// NOTE: async functions always return a Promise
const test = async () => { 
    let array1 = [], array2 = [];

    return {array1, array2};
};

Когда я позволяю PhpStorm генерировать документы, я получаю следующее:

/**
 * @returns {Promise.<{array1: Array, array2: Array}>}
 */
const test = async () => {
    let array1 = [], array2 = [];

    return {array1, array2};
};
Франческо Казула
источник
0

Вот что мне нравится делать (с чем я могу немного перестараться):

/**
 * @external Promise
 * @see {@link http://api.jquery.com/Types/#Promise Promise}
 */

/**
 * This callback is called when the result is loaded.
 *
 * @callback SuccessCallback
 * @param {string} result - The result is loaded.
 */

/**
 * This callback is called when the result fails to load.
 *
 * @callback ErrorCallback
 * @param {Error} error - The error that occurred while loading the result.
 */

/**
 * Resolves with a {@link SuccessCallback}, fails with a {@link ErrorCallback}
 *
 * @typedef {external:Promise} LoadResultPromise
 */

/**
 * Loads the result
 *
 * @returns {LoadResultPromise} The promise that the result will load.
 */
function loadResult() {
    // do something
    return promise;
}

По сути, определите базовое обещание со ссылкой на некоторую документацию (в этом случае я связываюсь с jQuery), определите свои обратные вызовы, которые будут вызываться, когда обещание либо разрешится, либо не удастся, а затем определите свое конкретное обещание, которое ссылается на обратная связь документация.

Наконец, используйте ваш конкретный тип обещания в качестве возвращаемого типа.

нильц
источник