actions-on-google / actions-on-google-nodejs

Node.js client library for Actions on Google
https://actions-on-google.github.io/actions-on-google-nodejs
Apache License 2.0
900 stars 194 forks source link

app type for Typescript plugins #157

Open joelhegg opened 6 years ago

joelhegg commented 6 years ago

https://developers.google.com/actions/reference/nodejs/lib-v1-migration gives the following example for writing a plugin:

const intentSet1 = app => {
  app.intent('intentSet1A', handler1A);
  app.intent('intentSet1B', handler1B);
};

If I'm working in Typescript, without app's type specified, this of course gives me the error:

Parameter 'app' implicitly has an 'any' type.

What's the best way to work around this error? If I just go by what's in the library it gets crazy verbose:

const intentSet1 = <TConvData, TUserStorage, TConversation extends ActionsSdkConversation<TConvData, TUserStorage>>(app: ActionsSdkApp<TConvData, TUserStorage, TConversation>) => {
  app.intent('intentSet1A', handler1A);
  app.intent('intentSet1B', handler1B);
};

In the latest version of Typescript (2.8) this gets better using ReturnType:

const intentSet1 = (app: ReturnType<typeof actionssdk>) => {
  app.intent('intentSet1A', handler1A);
  app.intent('intentSet1B', handler1B);
};

Can we get some direction on what's the best answer here? Maybe an exported alias along the lines of the ReturnType example above added to the library would help.

Canain commented 6 years ago

Yeah, the plugin system hasn't been completely battle tested yet so we can definitely add more helper types.

It was intended for developers to use the Plugin interface to create a plugin in TypeScript.

So in your example it looks like:

import { actionssdk, ActionsSdkApp, ActionsSdkConversation, Plugin } from 'actions-on-google';

const app = actionssdk();

const intentSet1: Plugin<ActionsSdkApp<{}, {}, ActionsSdkConversation<{}, {}>>, {}> = app => {
  app.intent('intentSet1A', handler1A);
  app.intent('intentSet1B', handler1B);
};

In the future, we can give default generic type parameters for ActionsSdkApp and Plugin so that it looks simpler for the basic use case.

const intentSet1: Plugin<ActionsSdkApp> = app => {
  app.intent('intentSet1A', handler1A);
  app.intent('intentSet1B', handler1B);
};

For more resources, take a look at the TypeScript snippets shared during the alpha:

And also this Stack Overflow post about TypeScript for middleware.

The primary focus of the library was to make it easy for JavaScript development which means it had a lot of dynamic type transformations. Unfortunately, this meant that the TypeScript to support it is pretty complicated but still ensures type checking for almost everything.

We haven't gotten a chance to go and simplify the types to give more defaults but can definitely work on it for the future.