From d6d5181d49daf3a157fcafcff710f26f189f19c6 Mon Sep 17 00:00:00 2001 From: jbernava Date: Sun, 2 Jul 2023 18:03:37 +0200 Subject: [PATCH 1/6] :sparkles: Improve type for delegate resolve flow --- framework/src/BaseDelegateComponent.ts | 30 ++++++++++++++++++++++++++ framework/src/Jovo.ts | 5 ++++- framework/src/index.ts | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 framework/src/BaseDelegateComponent.ts diff --git a/framework/src/BaseDelegateComponent.ts b/framework/src/BaseDelegateComponent.ts new file mode 100644 index 000000000..d7ccc6409 --- /dev/null +++ b/framework/src/BaseDelegateComponent.ts @@ -0,0 +1,30 @@ +import { UnknownObject } from '@jovotech/common'; +import { BaseComponent, ComponentData } from './'; + +export type ExtractDelegatedEventData< + T extends BaseDelegateComponent>, + KEY extends keyof T['__resolve'], +> = T extends BaseDelegateComponent ? RESOLVE[KEY] : never; + +export abstract class BaseDelegateComponent< + RESOLVE extends UnknownObject, + DATA extends ComponentData = ComponentData, + CONFIG extends UnknownObject = UnknownObject, +> extends BaseComponent { + // used to permit the ExtractDelegatedEventData work. + // If you find a better way that not require "declare", be my guest! :D + declare __resolve: RESOLVE; + + override async $resolve( + eventName: Extract, + ...eventArgs: ARGS extends Array ? ARGS : ARGS[] + ): Promise; + override async $resolve( + eventName: Extract, + eventArg: ARGS, + ): Promise { + // because of the JovoProxy class, this implementation of the $resolve will not be called. + // But it's ok, we need only types work. + return super.$resolve(eventName as string, ...(eventArg as unknown[])); + } +} diff --git a/framework/src/Jovo.ts b/framework/src/Jovo.ts index b5e3b5fbc..7171a1457 100644 --- a/framework/src/Jovo.ts +++ b/framework/src/Jovo.ts @@ -40,6 +40,8 @@ import { JovoRoute } from './plugins/RouterPlugin'; import { forEachDeep } from './utilities'; import { DependencyInjector } from './DependencyInjector'; import { v4 as uuidv4 } from 'uuid'; +import {BaseDelegateComponent} from "./BaseDelegateComponent"; + const DELEGATE_MIDDLEWARE = 'event.$delegate'; const RESOLVE_MIDDLEWARE = 'event.$resolve'; const REDIRECT_MIDDLEWARE = 'event.$redirect'; @@ -431,7 +433,8 @@ export abstract class Jovo< } // TODO determine whether an error should be thrown if $resolve is called from a context outside a delegation - async $resolve(eventName: string, ...eventArgs: ARGS): Promise { + // TODO Move the implementation to the BaseDelegatedComponent. So also the previously TODO can be removed. + async $resolve(eventName: string, ...eventArgs: ARGS): Promise { if (!this.$state) { return; } diff --git a/framework/src/index.ts b/framework/src/index.ts index bde6af054..7bb7d1480 100644 --- a/framework/src/index.ts +++ b/framework/src/index.ts @@ -47,6 +47,7 @@ export { export * from './App'; export * from './AsyncJovo'; export * from './BaseComponent'; +export * from './BaseDelegateComponent'; export * from './BaseOutput'; export * from './ComponentPlugin'; export * from './ComponentTree'; From e78640398b2401af61c4c0b5af14b5a670892ae8 Mon Sep 17 00:00:00 2001 From: jbernava Date: Sun, 2 Jul 2023 20:37:33 +0200 Subject: [PATCH 2/6] :sparkles: Improve type for delegate resolve flow --- framework/src/BaseDelegateComponent.ts | 2 +- framework/src/Jovo.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/framework/src/BaseDelegateComponent.ts b/framework/src/BaseDelegateComponent.ts index d7ccc6409..9102603bc 100644 --- a/framework/src/BaseDelegateComponent.ts +++ b/framework/src/BaseDelegateComponent.ts @@ -1,5 +1,5 @@ import { UnknownObject } from '@jovotech/common'; -import { BaseComponent, ComponentData } from './'; +import { BaseComponent, ComponentData } from './index'; export type ExtractDelegatedEventData< T extends BaseDelegateComponent>, diff --git a/framework/src/Jovo.ts b/framework/src/Jovo.ts index 7171a1457..c2831d84f 100644 --- a/framework/src/Jovo.ts +++ b/framework/src/Jovo.ts @@ -7,7 +7,7 @@ import util from 'util'; import { App, AppConfig } from './App'; import { HandleRequest } from './HandleRequest'; import { - BaseComponent, + BaseComponent, BaseDelegateComponent, BaseOutput, ComponentConfig, ComponentConstructor, @@ -40,7 +40,6 @@ import { JovoRoute } from './plugins/RouterPlugin'; import { forEachDeep } from './utilities'; import { DependencyInjector } from './DependencyInjector'; import { v4 as uuidv4 } from 'uuid'; -import {BaseDelegateComponent} from "./BaseDelegateComponent"; const DELEGATE_MIDDLEWARE = 'event.$delegate'; const RESOLVE_MIDDLEWARE = 'event.$resolve'; @@ -356,6 +355,12 @@ export abstract class Jovo< }); } + async $delegate>( + component: ComponentConstructor | string, + options: DelegateOptions, COMPONENT extends BaseDelegateComponent + ? keyof RESOLVE + : never>, + ): Promise async $delegate( constructor: ComponentConstructor, options: DelegateOptions>, From 0d6c4edaff37783783867b0fb431350f4b5570f3 Mon Sep 17 00:00:00 2001 From: jbernava Date: Sun, 2 Jul 2023 18:03:37 +0200 Subject: [PATCH 3/6] :sparkles: Improve type for delegate resolve flow --- framework/src/Jovo.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Jovo.ts b/framework/src/Jovo.ts index c2831d84f..8d1bfc632 100644 --- a/framework/src/Jovo.ts +++ b/framework/src/Jovo.ts @@ -40,7 +40,6 @@ import { JovoRoute } from './plugins/RouterPlugin'; import { forEachDeep } from './utilities'; import { DependencyInjector } from './DependencyInjector'; import { v4 as uuidv4 } from 'uuid'; - const DELEGATE_MIDDLEWARE = 'event.$delegate'; const RESOLVE_MIDDLEWARE = 'event.$resolve'; const REDIRECT_MIDDLEWARE = 'event.$redirect'; From a3c32b98e0fff778f9a80e10139e093f3d63509e Mon Sep 17 00:00:00 2001 From: jbernava Date: Thu, 6 Jul 2023 20:42:59 +0200 Subject: [PATCH 4/6] Removed a type from $resolved. --- framework/src/BaseDelegateComponent.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/framework/src/BaseDelegateComponent.ts b/framework/src/BaseDelegateComponent.ts index 9102603bc..6af3cd3df 100644 --- a/framework/src/BaseDelegateComponent.ts +++ b/framework/src/BaseDelegateComponent.ts @@ -1,5 +1,5 @@ -import { UnknownObject } from '@jovotech/common'; -import { BaseComponent, ComponentData } from './index'; +import {UnknownObject} from '@jovotech/common'; +import {BaseComponent, ComponentData} from './index'; export type ExtractDelegatedEventData< T extends BaseDelegateComponent>, @@ -18,13 +18,9 @@ export abstract class BaseDelegateComponent< override async $resolve( eventName: Extract, ...eventArgs: ARGS extends Array ? ARGS : ARGS[] - ): Promise; - override async $resolve( - eventName: Extract, - eventArg: ARGS, ): Promise { // because of the JovoProxy class, this implementation of the $resolve will not be called. // But it's ok, we need only types work. - return super.$resolve(eventName as string, ...(eventArg as unknown[])); + return super.$resolve(eventName as string, ...(eventArgs as unknown[])); } } From c9f36ec6557d5f2c121e95a5cfed58b417fda6a9 Mon Sep 17 00:00:00 2001 From: jbernava Date: Sat, 8 Jul 2023 15:00:46 +0200 Subject: [PATCH 5/6] Improve typing on $resolve --- framework/src/BaseDelegateComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/BaseDelegateComponent.ts b/framework/src/BaseDelegateComponent.ts index 6af3cd3df..debf1dd9b 100644 --- a/framework/src/BaseDelegateComponent.ts +++ b/framework/src/BaseDelegateComponent.ts @@ -17,7 +17,7 @@ export abstract class BaseDelegateComponent< override async $resolve( eventName: Extract, - ...eventArgs: ARGS extends Array ? ARGS : ARGS[] + ...eventArgs: ARGS extends Array ? [...ARGS] : [ARGS] ): Promise { // because of the JovoProxy class, this implementation of the $resolve will not be called. // But it's ok, we need only types work. From 42aa899b4baf6b5c86d6885a89c4b83e66ab8200 Mon Sep 17 00:00:00 2001 From: jbernava Date: Sat, 8 Jul 2023 16:18:22 +0200 Subject: [PATCH 6/6] Improve typing on $resolve Added a *breaking change* in Jovo.$resolve typing. I'm try to find a better way without the necessity to change the type of ARGS, but for now it's working for the delegateComponent. --- framework/src/BaseDelegateComponent.ts | 8 +++++--- framework/src/Jovo.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/framework/src/BaseDelegateComponent.ts b/framework/src/BaseDelegateComponent.ts index debf1dd9b..a6e3140bf 100644 --- a/framework/src/BaseDelegateComponent.ts +++ b/framework/src/BaseDelegateComponent.ts @@ -6,8 +6,10 @@ export type ExtractDelegatedEventData< KEY extends keyof T['__resolve'], > = T extends BaseDelegateComponent ? RESOLVE[KEY] : never; +type IsTuple = T extends [any, ...any] ? true : false + export abstract class BaseDelegateComponent< - RESOLVE extends UnknownObject, + RESOLVE extends Record, DATA extends ComponentData = ComponentData, CONFIG extends UnknownObject = UnknownObject, > extends BaseComponent { @@ -17,10 +19,10 @@ export abstract class BaseDelegateComponent< override async $resolve( eventName: Extract, - ...eventArgs: ARGS extends Array ? [...ARGS] : [ARGS] + ...eventArgs: ARGS extends Array ? (IsTuple extends true ? ARGS : [ARGS]) : [ARGS] ): Promise { // because of the JovoProxy class, this implementation of the $resolve will not be called. // But it's ok, we need only types work. - return super.$resolve(eventName as string, ...(eventArgs as unknown[])); + return super.$resolve(eventName as string, ...eventArgs); } } diff --git a/framework/src/Jovo.ts b/framework/src/Jovo.ts index 8d1bfc632..f89ddc874 100644 --- a/framework/src/Jovo.ts +++ b/framework/src/Jovo.ts @@ -438,7 +438,7 @@ export abstract class Jovo< // TODO determine whether an error should be thrown if $resolve is called from a context outside a delegation // TODO Move the implementation to the BaseDelegatedComponent. So also the previously TODO can be removed. - async $resolve(eventName: string, ...eventArgs: ARGS): Promise { + async $resolve(eventName: string, ...eventArgs: ARGS): Promise { if (!this.$state) { return; }