Skip to content

[FEATURE] [serverless-runtime-types] Simplify ServerlessCallback type #522

@ericbn

Description

@ericbn

Is your feature request related to a problem? Please describe.
The ServerlessCallback type has the following inconveniences when working with Twilio Serverless with TypeScript:

  1. The Twilio Functions documentation mentions that calling callback() with no arguments is valid, for when a default 200 response is all that's needed. It also mentions that the catch block could consist of console.error(error); callback(error); But a very simple Twilio Function code like below:
    import {
      Context,
      ServerlessCallback,
      ServerlessEventObject,
    } from "@twilio-labs/serverless-runtime-types/types";
    
    export function handler(
      context: Context,
      event: ServerlessEventObject,
      callback: ServerlessCallback,
    ) {
      try {
        // ...
        callback();
      } catch (error) {
        console.error(error);
        callback(error);
      }
    }
    fails to be compiled with tsc:
    src/function.private.ts:14:5 - error TS2554: Expected 1-2 arguments, but got 0.
    
    14     callback();
           ~~~~~~~~
    
      node_modules/@twilio-labs/serverless-runtime-types/types.d.ts:383:3
        383   error: null | Error | string | object,
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        An argument for 'error' was not provided.
    
    src/function.private.ts:17:14 - error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'string | object | Error | null'.
    
    17     callback(error);
                    ~~~~~
    
    Found 2 errors in the same file, starting at: src/function.private.ts:14
    
  2. Using jest to test a Twilio Function that responds a payload (e.g. callback(null, {answer: 42});) like below:
    import { context, event } from "./helpers/twilio";
    import { handler } from "../src/function-with-payload.private";
    
    describe("test", () => {
      it("should work", (done) => {
        handler(context, event, function callback(error, payload) {
          if (error) {
            done(error);
            return;
          }
          try {
            expect(payload.answer).toEqual(42);
            done();
          } catch (error) {
            done(error);
          }
        });
      });
    });
    fails with:
    ● Test suite failed to run
    
      tests/function-with-payload.test.ts:12:16 - error TS18048: 'payload' is possibly 'undefined'.
    
      12         expect(payload.answer).toEqual(42);
                        ~~~~~~~
      tests/function-with-payload.test.ts:12:24 - error TS2339: Property 'answer' does not exist on type 'string | number | boolean | object'.
        Property 'answer' does not exist on type 'string'.
    
      12         expect(payload.answer).toEqual(42);
                                ~~~~~~
    

Describe the solution you'd like
Change the ServerlessCallback type to be:

export type ServerlessCallback = (
  error?: any,
  payload?: any
) => void;

Describe alternatives you've considered
Alternative could be using only JS instead of TypeScript in the project, but we still prefer to insist on TypeScript for better maintainability.

Additional context
Both JSON.stringify and console.log accept any as the type of their parameters, which arguably should be the same type of the payload and error in the callback.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions