diff --git a/lib/http-incoming.js b/lib/http-incoming.js index 93f43dc..8beb358 100644 --- a/lib/http-incoming.js +++ b/lib/http-incoming.js @@ -10,6 +10,7 @@ const urlFromRequest = (request) => { }; /** + * @template {Record} [T=Record] * @typedef {object} PodiumHttpIncoming * @property {string} name * @property {object} context @@ -17,11 +18,12 @@ const urlFromRequest = (request) => { * @property {URL} url * @property {Array} css * @property {Array} js - * @property {object} [params] + * @property {T} [params] * @property {boolean} [development] * @property {boolean} [proxy] */ +/** @template {Record} [T=Record] */ export default class HttpIncoming { #development; #response; @@ -48,15 +50,17 @@ export default class HttpIncoming { #js; /** + * @constructor * @param {object} [request={}] The incoming HTTP request * @param {object} [response={}] The HTTP response - * @param {object} [params={}] Parameters such as locale. Typically res.locals. + * @param {T} [params={}] Parameters such as locale. Typically res.locals. * * @example * ```js * const incoming = new HttpIncoming(req, res, res.locals); * ``` */ + // @ts-expect-error Not happy about the generics, but this is safe constructor(request = {}, response = {}, params = {}) { this.#development = false; this.#response = response; @@ -143,6 +147,9 @@ export default class HttpIncoming { throw new Error('Cannot set read-only property.'); } + /** + * @returns {T} + */ get params() { return this.#params; } @@ -201,7 +208,7 @@ export default class HttpIncoming { } /** - * @returns {PodiumHttpIncoming} + * @returns {PodiumHttpIncoming} */ toJSON() { return { diff --git a/tests/http-incoming.test.js b/tests/http-incoming.test.js index 5b44e0b..d8b8d9f 100644 --- a/tests/http-incoming.test.js +++ b/tests/http-incoming.test.js @@ -125,6 +125,7 @@ tap.test('PodiumHttpIncoming.params - set value', (t) => { const incoming = new HttpIncoming(ADVANCED_REQ, SIMPLE_RES); t.throws( () => { + // @ts-ignore Testing bad input incoming.params = 'foo'; }, /Cannot set read-only property./, @@ -311,3 +312,17 @@ tap.test( t.end(); }, ); + +tap.test('generic typing works as expected', (t) => { + // really only here for tsc + + /** + * @template {{ [key: string]: unknown }} T + * @param {( incoming: HttpIncoming, fragment: string, ...args: unknown[]) => string} fn + * @returns {void} + */ + // eslint-disable-next-line no-unused-vars + function view(fn) {} + t.ok(view); + t.end(); +});