From 76f7d96bc822d8465c2a976a81637be204314488 Mon Sep 17 00:00:00 2001 From: szydlovski Date: Wed, 13 Oct 2021 21:34:43 +0200 Subject: [PATCH 1/4] feat: custom ts context --- src/App.ts | 45 +++++++++++++++++++++-------------------- src/types/middleware.ts | 6 ++++-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/App.ts b/src/App.ts index a60d7a2a4..acea4c89d 100644 --- a/src/App.ts +++ b/src/App.ts @@ -57,6 +57,7 @@ import { import { IncomingEventType, getTypeAndConversation, assertNever } from './helpers'; import { CodedError, asCodedError, AppInitializationError, MultipleListenerError, ErrorCode } from './errors'; import { AllMiddlewareArgs } from './types/middleware'; +import { StringIndexed } from './types/helpers'; // eslint-disable-next-line import/order import allSettled = require('promise.allsettled'); // eslint-disable-line @typescript-eslint/no-require-imports // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-commonjs @@ -174,7 +175,7 @@ class WebClientPool { /** * A Slack App */ -export default class App { +export default class App { /** Slack Web API client */ public client: WebClient; @@ -442,8 +443,8 @@ export default class App { * * @param m global middleware function */ - public use(m: Middleware): this { - this.middleware.push(m); + public use(m: Middleware): this { + this.middleware.push(m as Middleware); return this; } @@ -479,15 +480,15 @@ export default class App { public event( eventName: EventType, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public event( eventName: EventType, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public event( eventNameOrPattern: EventType, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void { let invalidEventName = false; if (typeof eventNameOrPattern === 'string') { @@ -513,9 +514,9 @@ export default class App { // TODO: just make a type alias for Middleware> // TODO: maybe remove the first two overloads - public message(...listeners: Middleware>[]): void; - public message(pattern: string | RegExp, ...listeners: Middleware>[]): void; - public message(...patternsOrMiddleware: (string | RegExp | Middleware>)[]): void { + public message(...listeners: Middleware, CustomContext>[]): void; + public message(pattern: string | RegExp, ...listeners: Middleware, CustomContext>[]): void; + public message(...patternsOrMiddleware: (string | RegExp | Middleware, CustomContext>)[]): void { const messageMiddleware = patternsOrMiddleware.map((patternOrMiddleware) => { if (typeof patternOrMiddleware === 'string' || util.types.isRegExp(patternOrMiddleware)) { return matchMessage(patternOrMiddleware); @@ -532,21 +533,21 @@ export default class App { public shortcut( callbackId: string | RegExp, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public shortcut< Shortcut extends SlackShortcut = SlackShortcut, Constraints extends ShortcutConstraints = ShortcutConstraints, >( constraints: Constraints, - ...listeners: Middleware>>[] + ...listeners: Middleware>, CustomContext>[] ): void; public shortcut< Shortcut extends SlackShortcut = SlackShortcut, Constraints extends ShortcutConstraints = ShortcutConstraints, >( callbackIdOrConstraints: string | RegExp | Constraints, - ...listeners: Middleware>>[] + ...listeners: Middleware>, CustomContext>[] ): void { const constraints: ShortcutConstraints = typeof callbackIdOrConstraints === 'string' || util.types.isRegExp(callbackIdOrConstraints) ? { callback_id: callbackIdOrConstraints } : @@ -572,7 +573,7 @@ export default class App { // https://basarat.gitbooks.io/typescript/docs/types/generics.html#design-pattern-convenience-generic public action( actionId: string | RegExp, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public action< Action extends SlackAction = SlackAction, @@ -580,14 +581,14 @@ export default class App { >( constraints: Constraints, // NOTE: Extract<> is able to return the whole union when type: undefined. Why? - ...listeners: Middleware>>[] + ...listeners: Middleware>, CustomContext>[] ): void; public action< Action extends SlackAction = SlackAction, Constraints extends ActionConstraints = ActionConstraints, >( actionIdOrConstraints: string | RegExp | Constraints, - ...listeners: Middleware>>[] + ...listeners: Middleware>, CustomContext>[] ): void { // Normalize Constraints const constraints: ActionConstraints = typeof actionIdOrConstraints === 'string' || util.types.isRegExp(actionIdOrConstraints) ? @@ -608,23 +609,23 @@ export default class App { this.listeners.push([onlyActions, matchConstraints(constraints), ...listeners] as Middleware[]); } - public command(commandName: string | RegExp, ...listeners: Middleware[]): void { + public command(commandName: string | RegExp, ...listeners: Middleware[]): void { this.listeners.push([onlyCommands, matchCommandName(commandName), ...listeners] as Middleware[]); } public options( actionId: string | RegExp, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; // TODO: reflect the type in constraits to Source public options( constraints: ActionConstraints, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; // TODO: reflect the type in constraits to Source public options( actionIdOrConstraints: string | RegExp | ActionConstraints, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void { const constraints: ActionConstraints = typeof actionIdOrConstraints === 'string' || util.types.isRegExp(actionIdOrConstraints) ? { action_id: actionIdOrConstraints } : @@ -635,15 +636,15 @@ export default class App { public view( callbackId: string | RegExp, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public view( constraints: ViewConstraints, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void; public view( callbackIdOrConstraints: string | RegExp | ViewConstraints, - ...listeners: Middleware>[] + ...listeners: Middleware, CustomContext>[] ): void { const constraints: ViewConstraints = typeof callbackIdOrConstraints === 'string' || util.types.isRegExp(callbackIdOrConstraints) ? { callback_id: callbackIdOrConstraints, type: 'view_submission' } : diff --git a/src/types/middleware.ts b/src/types/middleware.ts index 3305e27a9..b0000af51 100644 --- a/src/types/middleware.ts +++ b/src/types/middleware.ts @@ -24,10 +24,12 @@ export interface AllMiddlewareArgs { next: NextFn; } +export type ExtendContext = { context: T }; + // NOTE: Args should extend AnyMiddlewareArgs, but because of contravariance for function types, including that as a // constraint would mess up the interface of App#event(), App#message(), etc. -export interface Middleware { - (args: Args & AllMiddlewareArgs): Promise; +export interface Middleware { + (args: Args & AllMiddlewareArgs & ExtendContext): Promise; } /** From 8d453b8d1a0e3beb16e9a03899d22cd760c29438 Mon Sep 17 00:00:00 2001 From: szydlovski Date: Wed, 13 Oct 2021 21:55:14 +0200 Subject: [PATCH 2/4] fix: lint errors --- src/App.ts | 7 +++++-- src/types/middleware.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/App.ts b/src/App.ts index acea4c89d..a0eee3313 100644 --- a/src/App.ts +++ b/src/App.ts @@ -175,7 +175,7 @@ class WebClientPool { /** * A Slack App */ -export default class App { +export default class App { /** Slack Web API client */ public client: WebClient; @@ -609,7 +609,10 @@ export default class App { this.listeners.push([onlyActions, matchConstraints(constraints), ...listeners] as Middleware[]); } - public command(commandName: string | RegExp, ...listeners: Middleware[]): void { + public command( + commandName: string | RegExp, + ...listeners: Middleware[] + ): void { this.listeners.push([onlyCommands, matchCommandName(commandName), ...listeners] as Middleware[]); } diff --git a/src/types/middleware.ts b/src/types/middleware.ts index b0000af51..482aa13b9 100644 --- a/src/types/middleware.ts +++ b/src/types/middleware.ts @@ -24,11 +24,11 @@ export interface AllMiddlewareArgs { next: NextFn; } -export type ExtendContext = { context: T }; +export interface ExtendContext { context: T }; // NOTE: Args should extend AnyMiddlewareArgs, but because of contravariance for function types, including that as a // constraint would mess up the interface of App#event(), App#message(), etc. -export interface Middleware { +export interface Middleware { (args: Args & AllMiddlewareArgs & ExtendContext): Promise; } From 7170889e1bd42f155cf1a954049cb30757e8bfa2 Mon Sep 17 00:00:00 2001 From: szydlovski Date: Wed, 13 Oct 2021 21:57:48 +0200 Subject: [PATCH 3/4] fix: lint error --- src/types/middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/middleware.ts b/src/types/middleware.ts index 482aa13b9..c48898692 100644 --- a/src/types/middleware.ts +++ b/src/types/middleware.ts @@ -24,7 +24,7 @@ export interface AllMiddlewareArgs { next: NextFn; } -export interface ExtendContext { context: T }; +export interface ExtendContext { context: T } // NOTE: Args should extend AnyMiddlewareArgs, but because of contravariance for function types, including that as a // constraint would mess up the interface of App#event(), App#message(), etc. From a799388b5ca1a245c947e0e8e6834c6b18079830 Mon Sep 17 00:00:00 2001 From: szydlovski Date: Wed, 13 Oct 2021 22:52:57 +0200 Subject: [PATCH 4/4] refactor: add custom context at AllMiddlewareArgs instead of Middleware --- src/types/middleware.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/types/middleware.ts b/src/types/middleware.ts index c48898692..49692c11d 100644 --- a/src/types/middleware.ts +++ b/src/types/middleware.ts @@ -17,19 +17,17 @@ export type AnyMiddlewareArgs = | SlackViewMiddlewareArgs | SlackShortcutMiddlewareArgs; -export interface AllMiddlewareArgs { - context: Context; +export interface AllMiddlewareArgs { + context: Context & CustomContext; logger: Logger; client: WebClient; next: NextFn; } -export interface ExtendContext { context: T } - // NOTE: Args should extend AnyMiddlewareArgs, but because of contravariance for function types, including that as a // constraint would mess up the interface of App#event(), App#message(), etc. export interface Middleware { - (args: Args & AllMiddlewareArgs & ExtendContext): Promise; + (args: Args & AllMiddlewareArgs): Promise; } /**