functions-framework-nodejs icon indicating copy to clipboard operation
functions-framework-nodejs copied to clipboard

Better type annotation for cloudevent functions

Open matthewrobertson opened this issue 4 years ago • 3 comments

Now that we have the declarative functions signatures API we should be able to use the type annotations in https://github.com/googleapis/google-cloudevents-nodejs to provide a strong type information for cloudevent data payloads.

matthewrobertson avatar Oct 08 '21 22:10 matthewrobertson

How did we want the interface to be for the optional type annotation for CloudEvent data types?

Would this work for both declarative and non-declarative functions?

I could imagine a couple JS interfaces:

Option 1

User dependency on @google/events:

const {toLogEntryData} = require('@google/events/cloud/audit/v1/LogEntryData');

export function (cloudevent, toLogEntryData) => {
  console.log(cloudevent.data); // should have types
};

Option 2

FF dependency on @google/events:

exports.helloCloudEvents = async (cloudevent, 'google.events.cloud.audit.v1.LogEntryData') => {
  console.log(cloudevent.data); // should have types
};

grant avatar Oct 15 '21 23:10 grant

I prototyped a version of type annotation in this branch:

https://github.com/GoogleCloudPlatform/functions-framework-nodejs/compare/grant_declarative_types?expand=1

grant avatar Oct 19 '21 23:10 grant

I think we shouldn't be passing around value constructs at runtime in order to influence the TS type checker. The TS type system only exists at compile time. Passing around values and calling functions to change the type is kind of an antipattern, because normally all that stuff is dropped at compile time.

I think the right pattern here is to use generics and discriminated unions:

const {LogEntryData} = require('@google/events/cloud/audit/v1/LogEntryData');
functions.cloudevent<LogEntryData>('HelloWorld', (ce) => {
});

or this would also work:

functions.cloudevent('HelloWorld', (ce) => {
  if (ce.type === 'google.events.cloud.audit.v1.LogEntryData') {
   ce.data; // is strongly typed now
  }
});

an alternative is to use the typename as the generic param:

functions.cloudevent<'google.events.cloud.audit.v1.LogEntryData'>('HelloWorld', (ce) => {
});

matthewrobertson avatar Oct 25 '21 16:10 matthewrobertson