Jak określić rozdzielczość i typ odrzucenia promesy w JSDoc?

84

Mam kod, który zwraca obiekt obietnicy, np. Używając biblioteki Q dla NodeJS.

var Q = require('q');

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

Jak udokumentować taką zwracaną wartość za pomocą JSDoc?

Arikon
źródło
Zastanawiałem się nad czymś podobnym. Jak udokumentować zwracany typ funkcji, która może zwracać wiele różnych rzeczy na podstawie danych wejściowych i stanu aplikacji?
Hoffmann
Użyj składni wieloznacznej : @returns {*}
Paul Sweatte
Składnia symboli wieloznacznych nie jest tak specyficzna i nie pomaga.
Arikon,
2
@arikon Czy @returns {ErrorObject|ResultObject}pomaga? Używanie opisu typu „potok” jest powszechną praktyką.
John Doe,
3
@ john-doe Nie, tak nie jest. Ponieważ funkcja zwraca obiekt Promise, a nie tylko wynik lub błąd.
Arikon,

Odpowiedzi:

77

Nawet jeśli nie istnieją w Javascript, stwierdziłem, że JSdoc rozumie „typy ogólne”.

Możesz więc zdefiniować własne typy, a następnie użyć /* @return Promise<MyType> */. Poniższy wynik daje ładny TokenConsume (token) → {Promise. <Token>} z linkiem do twojego niestandardowego Tokentypu w dokumencie.

/**
 * @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
}

Działa nawet z /* @return Promise<MyType|Error> */lub /* @return Promise<MyType, Error> */.

jillro
źródło
1
@Sebastian tak, to jest idea!
jillro
W przypadku YUIDoc stwierdziłem, że to działa:@return {Promise|Token}
J Chris A
dobry pomysł! zmodyfikowałem go na:@returns {Promise<ForumPost>|Promise<false>|Error}
Przemek Lewandowski
1
Zdecydowanie nie podoba mi się to rozwiązanie, ponieważ jsdoc oddziela typedef na inną stronę niż funkcja, która ją zwraca. Wymaga również nazwania wszystkich rozpoznawalnych typów obiektów, ale wszystko, co naprawdę chcesz zrobić, to zwrócić wiele wartości i zawinąć je w obiekt.
Bob McElrath
2
Aktualizacja od właściciela projektu na temat obecnego rozwiązania i tego, co jest planowane do wydania github.com/jsdoc3/jsdoc/issues/1197#issuecomment-312948746
Mike Grace
7

Zwykle definiuję zewnętrzny typ obietnicy:

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

Teraz możesz opisać w @returnoświadczeniu dokumentacji funkcji, co dzieje się z obietnicą:

/**
* @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');
}
miracula
źródło
6

Dzięki JSDoc możesz również tworzyć niestandardowe typy za pomocą @typedef. Używam tego dość często, więc rekwizyty / parametry, które są łańcuchami lub tablicami, odsyłają do opisu typu (na przykład stringutworzyłem typedef, który zawiera rodzime dostępne dla stringów (zobacz przykład JSDoc poniżej). Możesz zdefiniować niestandardowy typ w ten sam sposób. Dzieje się tak, ponieważ nie można używać notacji z kropką obiektu do zwracania, tak jak w przypadku @property do oznaczania tego, co jest w wyniku zwrotnym. Dlatego w przypadkach, gdy zwracasz coś w rodzaju obiektu, możesz utworzyć definicję dla tego typu (' @typedef MyObject), a następnie @returns {myObject} Definition of myObject.

Nie zwariowałbym jednak na tym punkcie, ponieważ typy powinny być jak najbardziej dosłowne i nie chcesz zanieczyszczać swoich typów, ale są przypadki, w których chcesz jawnie zdefiniować typ, więc możesz udokumentować, co jest w nim (dobrym przykładem jest Modernizr ... zwraca obiekt, ale nie masz jego dokumentacji, więc utwórz niestandardową definicję typu, która szczegółowo określa, co jest w tym zwracanym wyniku).

Jeśli nie musisz iść tą trasą, to jak ktoś już wspomniał, możesz określić wiele typów dla dowolnego @param, @property lub @return, używając potoku |.

W twoim przypadku, należy również udokumentować @throws, ponieważ jesteś rzucanie 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
*/
burza cieni
źródło
1
Niestety, to nie działa w PHPStorm, który podświetla typ w @typedeftagu jako nierozwiązany. Tak, duh, definiuję to tutaj!
David Harkness
Ja nie rzuca błąd, po prostu tworząc swoje wystąpienie przekazać go do Q.reject ()
Arikon
6

Składnia obecnie obsługiwana przez 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() {
     // ...
};

Obsługiwane w przyszłości?

/**
 * 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() {
    // ...
};

Zobacz dyskusję na githubie: https://github.com/jsdoc3/jsdoc/issues/1197

holmberd
źródło
1
Właśnie znalazłem to samo. Link do komentarza wymienionego powyżej od właściciela projektu github.com/jsdoc3/jsdoc/issues/1197#issuecomment-312948746
Mike Grace
5

Jest też inny sposób na zrobienie tego, nawet jeśli może to być ODRADZANE . Nacisk na moc, ponieważ ktoś mówi, że jest przestarzały (sprawdź komentarze do tej odpowiedzi), podczas gdy inni twierdzą, że którykolwiek jest w porządku. Tak czy inaczej zgłaszam to ze względu na kompletność.

Teraz weźmy Promise.all()na przykład, który zwraca Obietnicę wypełnioną tablicą. Ze stylem notacji kropkowej wyglądałoby to tak, jak pokazano poniżej:

{Promise.<Array.<*>>}

Działa na produktach JetBrains (np. PhpStorm, WebStorm) i jest również używany w dokumentacji jsforce .

W chwili pisania tego tekstu, gdy próbuję automatycznie generować niektóre dokumenty za pomocą PHPStorm , domyślnie jest to ten styl, mimo że znalazłem do niego słabe odniesienie.

W każdym razie, jeśli weźmiesz następującą funkcję jako przykład:

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

    return {array1, array2};
};

Kiedy pozwalam PhpStorm generować dokumenty, otrzymuję to:

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

    return {array1, array2};
};
Francesco Casula
źródło
0

Oto, co lubię robić (co może być trochę przesadzone):

/**
 * @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;
}

Zasadniczo zdefiniuj podstawową obietnicę za pomocą linku do jakiejś dokumentacji (w tym przypadku odsyłam do jQuery), zdefiniuj swoje wywołania zwrotne, które zostaną wywołane, gdy obietnica zostanie rozwiązana lub nie powiedzie się, a następnie zdefiniuj swoją konkretną obietnicę, która łączy się z dokumentacja zwrotna.

Na koniec użyj określonego typu obietnicy jako typu zwrotu.

niltz
źródło