typescript - JSDoc: @callback med @property?
Jag använder JSDoc och har följande definition för Stream<T>:
/**
* @template T
* @callback Stream
*
* @param {T} [value]
*
* @return {T} the value
*/
Detta översätts korrekt till följande definition i index.d.ts:
export type Stream<T> = (value?: T) => T;
Men en Stream är en funktion som också har en map-egenskap. map är en funktion som skapar en annan stream:
const s = stream(); // s is a Stream
s(5); // s is a function
// but s.map is also a function
const s2 = s.map(x => x + 1);
Hur definierar jag Stream<T> med JSDoc? Följande fungerar inte:
/**
* @template T
* @callback Stream
*
* @param {T} [value]
* @property {Function} map
*
* @return {T} the value
*/
Det genererar inte map och ännu värre, förlorar faktumet att funktionen returnerar T:
export type Stream<T> = (value?: T) => any;
Idealiskt skulle jag vilja att detta (eller motsvarande) genereras:
export interface Stream<T> {
(value?: T) => T;
map<U>(fn: (value: T) => U): Stream<U>;
}
Finns det ett sätt att uppnå detta med JSDoc?
Svar #1
När det gäller VSCode:s intellisense har jag kommit fram till att implementera något liknande, för att definiera typ för callback med hjälp av JSDoc. Det kan också fungera i det här fallet.
Jag har inte stött på att definiera gränssnittstyper direkt i JSDoc-kommentarer, men det kan definieras direkt på den faktiska implementeringen. Först definieras funktionens ström:
/**
* @template T
* @function Stream
*
* @param {T} [value]
*
* @return {T} the value
*/
function Stream(value) {
//@ts-ignore
return value;
}
Jag ändrade @callback-taggen till @function, eftersom annars typen Stream blir fel tillsammans med Stream.map-egenskapen som definierats:
Stream(); // (local function) Stream(value: any): any
Nästa definieras egenskapskartan.
/**
* @template T inputted value
* @template U mapped value
*
* @param {(value: T) => U} fn
*/
Stream.map = function (fn) {
return fn;
};
Som ett resultat är s en 'interface'-funktion med map-egenskap som en metod.
// intellisense shows type similar to asked Stream interface:
// const s: {
// <T>(value?: T | undefined): T;
// map<T, U>(fn: (value: T) => U): (value: T) => U;
// }
const s = Stream;
// const s: <5>(value?: 5 | undefined) => 5
s(5);
const s2 = s.map(
/** @param {number} x */
x => x + 1
);
// const s2: (value: number) => number
s2(8);
// const s3: (value: string) => Error
const s3 = s.map(
/** @param {string} x */
x => new Error(x)
);
