diff --git a/lib/index.d.ts b/lib/index.d.ts index 13c91fe..e792304 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,7 +1,15 @@ import { Id, PolicyOptions } from '@hapi/catbox'; import { CachePolicyOptions, Plugin, Request, ResponseToolkit, Server, ServerOptionsCache } from '@hapi/hapi'; + declare namespace yar { + + export interface YarValues {} + export interface YarFlashes {} + + type YarValKeys = keyof YarValues; + type YarFlashKeys = keyof YarFlashes; + interface YarOptions { /** * Determines the name of the cookie used to store session information. @@ -109,20 +117,26 @@ declare namespace yar { /** * - assigns a value (string, object, etc) to a given key which will persist across requests. Returns the value. */ - set(key: string, value: T): T; + set(key: T, value: YarValues[T]): YarValues[T]; + set(key: string, value: T): T; + + /** * assigns values to multiple keys using each 'keysObject' top-level property. Returns the keysObject. */ - set(keysObject: T): T; + set>(keysObject: T): T; + set>(keysObject: T): T; /** * retrieve value using a key. If 'clear' is 'true', key is cleared on return. */ - get(key: string, clear?: boolean): any; + get (key: T, clear?: boolean): YarValues[T] | null; + get (key: string, clear?: boolean): T | null; /** * clears key. */ - clear(key: string): void; + clear (key: T): void; + clear (key: string): void; /** * Manually notify the session of changes (when using get() * and changing the content of the returned reference directly without calling set()). @@ -136,7 +150,10 @@ declare namespace yar { * 'isOverride' used to indicate that the message provided should replace * any existing value instead of being appended to it (defaults to false). */ - flash(type?: string, message?: any, isOverride?: boolean): any[]; + flash (type: T, message: YarFlashes[T], isOverride?: boolean): YarFlashes[T][]; + flash (type: string, message: T, isOverride?: boolean): T[]; + flash (type: T): YarFlashes[T][]; + flash (): { [key in keyof T]: T[key][] }; /** * if set to 'true', enables lazy mode. @@ -160,7 +177,9 @@ declare namespace yar { revoke(id: Id): Promise; } } + declare const yar: Plugin; + export = yar; declare module '@hapi/hapi' { diff --git a/test/types/index.ts b/test/types/index.ts index 6ef0bfe..1a47c90 100644 --- a/test/types/index.ts +++ b/test/types/index.ts @@ -1,6 +1,31 @@ +import * as lab from '@hapi/lab'; import { Request, Server } from '@hapi/hapi'; import * as yar from '../..'; +const { expect } = lab.types; + +declare module '../..' { + + interface YarValues { + + test1: string; + test2: { + a: true; + b: string; + }, + + example: { + key: string; + }; + } + + interface YarFlashes { + + success: { title: string; message: string; type: 'success' }; + error: { title: string; message: string; type: 'error' }; + } +} + async function boot() { const server = new Server(); await server.register({ @@ -21,10 +46,147 @@ async function boot() { path: '/test', method: 'get', handler(request: Request) { + + /** Typed YarValues */ const example = request.yar.get('example'); + + expect.error( + request.yar.get('test1') === 123 + ); + + const test1 = request.yar.get('test1'); + const test2 = request.yar.get('test2'); + + test1 === '1233'; + test2?.a === true; + + expect.type(test1); + expect.type<{ a: true; b: string } | null>(test2); + + + /** Untyped YarValues */ + const test3 = request.yar.get <{ something: 'else' }>('test3'); + + expect.type<{ something: 'else' } | null>(test3); + + expect.error( + request.yar.get ('test4') === 123 + ); + + + return { + id: request.yar.id, + key: example?.key, + }; + }, + }); + + server.route({ + + path: '/test', + method: 'post', + handler(request: Request) { + + /** Typed YarValues */ + expect.type( + request.yar.set('test1', '123') + ); + + expect.error( + request.yar.set('test1', 123) + ); + + expect.type( + request.yar.set('test2', { + a: true, + b: '123', + }) + ); + + const partialYarObj = { + test1: '123', + }; + + expect.type>(request.yar.set(partialYarObj)); + + expect.error>( + request.yar.set({ bad: 'type' }) + ); + + + /** Untyped YarValues */ + + expect.type<{ good: 'type' }>( + request.yar.set({ good: 'type' }) + ); + + expect.type( + request.yar.set('anything', true) + ); + + + /** Typed YarFlashes */ + expect.type( + + request.yar.flash('error', { + title: 'Error', + message: 'This is an error', + type: 'error' + }) + ); + + expect.type( + request.yar.flash('success', { + title: 'Success', + message: 'This is a success', + type: 'success' + }) + ); + + expect.error( + request.yar.flash('info', 'message') + ) + + expect.type( + request.yar.flash('error') + ) + + expect.type( + request.yar.flash('success') + ) + + expect.error( + request.yar.flash('error') + ) + + expect.type<{ [k in keyof yar.YarFlashes]: yar.YarFlashes[k][] }>( + request.yar.flash() + ); + + /** Untyped YarFlashes */ + + expect.type( + request.yar.flash('info', 'message') + ) + + + type OtherFlash = { + name: string; + text: string; + } + + type CustomFlashes = { + + info: OtherFlash + warning: OtherFlash + }; + + expect.type<{ [key in keyof CustomFlashes]: OtherFlash[] }>( + request.yar.flash () + ); + return { id: request.yar.id, - key: example.key, }; }, });