Similar to a discussion on unit testing with typescript, I am puzzled by the incompatibility of the Partial type with the full version.
In my unit test scenario, I need to check if a lambda returns 400 when the body in an AWS lambda event is not valid. To keep things simple and clear for my colleagues, I want to avoid creating unnecessary noise by using a Partial<APIGatewayProxyEvent> instead of creating a complete invalidEvent with all properties of APIGatewayProxyEvent.
it("should return 400 when request event is invalid", async () => {
const invalidEvent: Partial<APIGatewayProxyEvent> = {
body: JSON.stringify({ foo: "bar" }),
};
const { statusCode } = await handler(invalidEvent);
expect(statusCode).toBe(400);
});
However, the line
const { statusCode } = await handler(invalidEvent);
fails compilation due to:
Argument of type 'Partial<APIGatewayProxyEvent>' is not assignable to parameter of type 'APIGatewayProxyEvent'.
Types of property 'body' are incompatible.
Type 'string | null | undefined' is not assignable to type 'string | null'.
Type 'undefined' is not assignable to type 'string | null'.ts(2345)
I understand that the body of APIGatewayProxyEvent can be string or null, but why does it show as string or null or undefined? Why is my string not considered a valid body for APIGatewayProxyEvent?
How can TypeScript Partials be effectively used to test AWS Lambda functions?
The usage of as
for type assertions could be an alternative approach, but I prefer the clarity provided by Partials. Although, the following code also works:
const invalidEvent = { body: JSON.stringify({ foo: "bar" }) } as APIGatewayProxyEvent;
Update: utilizing Omit and Pick to define a new type
type TestingEventWithBody = Omit<Partial<APIGatewayProxyEvent>, "body"> & Pick<APIGatewayProxyEvent, "body">;
it("should return 400 when request event is invalid", async () => {
const invalidEvent: TestingEventWithBody = { body: JSON.stringify({ foo: "bar" }) };
const { statusCode } = await handler(invalidEvent);
expect(statusCode).toBe(400);
});
This attempt results in:
Argument of type 'TestingEventWithBody' is not assignable to parameter of type 'APIGatewayProxyEvent'.
Types of property 'headers' are incompatible.
Type 'APIGatewayProxyEventHeaders | undefined' is not assignable to type 'APIGatewayProxyEventHeaders'.
Type 'undefined' is not assignable to type 'APIGatewayProxyEventHeaders'.ts(2345)