I have this validation middleware that I'm trying to write to validate an empty payload when sending requests :
const _isMissing = (body: any): boolean => !body;
export const isMissing = Object.defineProperty(_isMissing, '_apiGatewayResponse', {
value: LAMBDA_400_RESPONSE,
});
interface ValidationFunction extends Function {
_apiGatewayResponse: APIGatewayProxyResult;
}
export function validateRequestBody(
handler: LambdaFunction,
validations: Array<ValidationFunction>,
): LambdaFunction {
const wrapper: LambdaFunction = async (
event: APIGatewayEvent,
): Promise<APIGatewayProxyResult> => {
const eventBody = event.body ? JSON.parse(event.body) : null;
for (const validation of validations) {
const invalidBody = validation(eventBody);
if (invalidBody) {
return validation._apiGatewayResponse || LAMBDA_400_RESPONSE;
}
}
const response = await handler(event);
return response;
};
return wrapper;
}
But when I come to use the middleware function :
validateRequestBody(myPostFunction, [isMissing]);
I get a TypeScript error on isMissing
stating
Property '_apiGatewayResponse' is missing in type '(body: any) => boolean' but required in type 'ValidationFunction'.
Can anyone help me resolve this? I couldn't really find any similar problems and would appreciate any help.
Thank you!
CodePudding user response:
The type of isMissing
(which comes from _isMissing
) is (body: any) => boolean
(a function accepting a single parameter of type any
and returning a boolean
), but ValidationFunction
requires an _apiGatewayResponse
property on it. Even though you add the property at runtime via Object.defineProperty
, that doesn't change the compile-time type that the function has.
You can assure TypeScript that the result has the right type via an innocuous type assertion that only asserts what you can easily see the code is adding. For example:
type IsMissingFunction = ((body: any) => boolean) & ValidationFunction;
const _isMissing = (body: any): boolean => !body;
export const isMissing: IsMissingFunction = Object.defineProperty(
_isMissing as typeof _isMissing & Pick<ValidationFunction, "_apiGatewayResponse">,
'_apiGatewayResponse', {
value: LAMBDA_400_RESPONSE
}
);
You could just use as IsMissingFunction
instead of the more long-winded as typeof _isMissing & Pick<ValidationFunction, "_apiGatewayResponse">
:
type IsMissingFunction = ((body: any) => boolean) & ValidationFunction;
const _isMissing = (body: any): boolean => !body;
export const isMissing: IsMissingFunction = Object.defineProperty(
_isMissing as IsMissingFunction,
'_apiGatewayResponse', {
value: LAMBDA_400_RESPONSE
}
);
The reason I prefer the first version is that if you edit IsMissingFunction
(or ValidationFunction
) later to add more properties, TypeScript will raise a helpful error on the first example indicating that the function no longer fits the definition of IsMissingFunction
. With the second example, you'd have to make a really big change for it to complain.