jovotech / jovo-framework

🔈 The React for Voice and Chat: Build Apps for Alexa, Messenger, Instagram, the Web, and more
https://www.jovo.tech
Apache License 2.0
1.67k stars 310 forks source link

:sparkles: Add type checking to resolve object #1592

Closed acerbisgianluca closed 5 months ago

acerbisgianluca commented 10 months ago

closes #1591

Proposed Changes

Add type checking to this.$delegate(...) resolve object and to this.$resolve(...).

If EVENTS type isn't passed to the extended BaseComponent, Jovo should behave as usual.

If EVENTS type is set, then IDE will provide autocompletion for resolve keys and for the event name in this.$resolve(eventName).

Types of Changes

Checklist

acerbisgianluca commented 10 months ago

In the previous commit I've reverted the changes made to JovoComponentInfo in favor of using the infer keyword to infer the correct type from the BaseComponent's generics. As a result, I had to override the $resolve function in BaseComponent class in order to have access to the EVENTS generic type. In the case of $delegate I didn't need to do that, because we pass the component class to the function, so TS is able to automatically infer the correct type. I believe we can use the infer keyword to infer the CONFIG type as well, but I've left as is. Let me know if I should change that.

aswetlow commented 10 months ago

Hey @acerbisgianluca

Thank you for the PR. This is really useful. Do you have a working example?

acerbisgianluca commented 10 months ago

@aswetlow Sure. You can try it in framework/test/e2e.test.ts (these lines) with your IDE by using the following code:

@Component({ global: true })
    class GlobalComponent extends BaseComponent {
      [BuiltInHandler.Launch]() {
        return this.$delegate(DelegateTargetComponent, {
          resolve: {
            onNo: this.onFinishDelegate,
          },
        });
      }

      onFinishDelegate() {
        return this.$send('Finish');
      }
    }

    @Component()
    class DelegateTargetComponent extends BaseComponent<{}, {}, 'onYes' | 'onNo'> {
      [BuiltInHandler.Start]() {
        return this.$send('Hello world');
      }

      async [BuiltInHandler.Unhandled]() {
        return this.$resolve('onYes');
      }
    }