I have problem with Zod’s coerce method. I know that by default req.params are string, but I’ve thought that coerce method would change it to number during parsing, so it would work.
ValidateSchema.ts
import z from "zod";
const toNumber = z.coerce.number();
const toDate = z.coerce.date();
export const getWeatherForLocationSchema = z.object({
params: z.object({
lat: z.string().pipe(z.coerce.number()),
lon: z.string().pipe(z.coerce.number()),
// lat: z.string().transform((data) => +data),
// lat: z.string(),
// lon: z.string(),
}),
});
export type getCurrentWeatherForLocationRequest = z.infer<
typeof getWeatherForLocationSchema
>;
WeatherController.ts
getCurrentWeatherForLocation = async (
req: ParsedRequest<getCurrentWeatherForLocationRequest>,
res: Response
) => {
const lat = req.params.lat;
const lon = req.params.lon;
console.log(typeof lat);
const weather = await this.weatherService.getCurrentWeatherForLocation(
lat,
lon
);
res.status(200).json(weather);
};
WeatherRouter.ts
"/weather/locations/:lat/:lon",
validatorMiddleware(getWeatherForLocationSchema),
weatherController.getCurrentWeatherForLocation
);
ValidatorMiddleware.ts
import { SafeParseReturnType, Schema, ZodError } from "zod";
import { ExpressAnyRequestData } from "../interfaces/ApiTypes";
import { NextFunction, Request, Response } from "express";
import { ParsedQs } from "qs";
export function validateExpressRequest<T extends ExpressAnyRequestData>(
schema: Schema<T>,
req: Request
): T {
const { params, query, body } = req;
const dataToParse: {
params?: Record<string, string>;
query?: ParsedQs;
body?: unknown;
} = {};
if (Object.keys(params).length) {
dataToParse.params = params;
}
if (query && Object.keys(query).length) {
dataToParse.query = query;
}
if (Object.keys(body).length) {
dataToParse.body = body;
}
const validationResult: SafeParseReturnType<
{
params?: Record<string, string>;
query?: ParsedQs;
body?: unknown;
},
{ params?: any; query?: any; body?: any }
> = schema.safeParse(dataToParse);
if (!validationResult.success) {
throw new ZodError(validationResult.error.issues);
}
return {
query: validationResult.data.query,
params: validationResult.data.params,
body: validationResult.data.body,
} as T;
}
export function validatorMiddleware(
schema: Schema
): (req: Request, res: Response, next: NextFunction) => void {
return (req: Request, res: Response, next: NextFunction): void => {
try {
const result = validateExpressRequest(schema, req);
const { params, query, body } = result;
req.query = query;
req.params = params;
req.body = body;
return next();
} catch (e) {
return next(e);
}
};
}
My error:
usr/local/lib/node_modules/ts-node/src/index.ts:859
return new TSError(diagnosticText, diagnosticCodes, diagnostics);
^
TSError: ⨯ Unable to compile TypeScript:
src/domains/weather/WeatherRouter.ts:18:3 - error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type '(req: ParsedRequest<getCurrentWeatherForLocationRequest>, res: Response) => Promise<void>' is not assignable to parameter of type 'RequestHandlerParams<ParamsDictionary, any, unknown, ParsedQs, {}>'.
Type '(req: ParsedRequest<getCurrentWeatherForLocationRequest>, res: Response) => Promise<void>' is not assignable to type 'RequestHandler<ParamsDictionary, any, unknown, ParsedQs, {}>'.
Types of parameters 'req' and 'req' are incompatible.
Type 'Request<ParamsDictionary, any, unknown, ParsedQs, {}>' is not assignable to type 'ParsedRequest<{ params: { lat: number; lon: number; }; }>'.
Types of property 'params' are incompatible.
Type 'ParamsDictionary' is missing the following properties from type '{ lat: number; lon: number; }': lat, lon
18 weatherController.getCurrentWeatherForLocation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@types/express-serve-static-core/index.d.ts:153:5
153 <
~
154 P = ParamsDictionary,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
162 ...handlers: Array<RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, LocalsObj>>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
163 ): T;
~~~~~~~~~
The last overload is declared here.
at createTSError (/usr/local/lib/node_modules/ts-node/src/index.ts:859:12)
at reportTSError (/usr/local/lib/node_modules/ts-node/src/index.ts:863:19)
at getOutput (/usr/local/lib/node_modules/ts-node/src/index.ts:1077:36)
at Object.compile (/usr/local/lib/node_modules/ts-node/src/index.ts:1433:41)
at Module.m._compile (/usr/local/lib/node_modules/ts-node/src/index.ts:1617:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Object.require.extensions.<computed> [as .ts] (/usr/local/lib/node_modules/ts-node/src/index.ts:1621:12)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Function.Module._load (node:internal/modules/cjs/loader:960:12)
at Module.require (node:internal/modules/cjs/loader:1143:19) {
diagnosticCodes: [ 2769 ]
}
[nodemon] app crashed - waiting for file changes before starting...
I want to add conversion type without need to change in controller method. I’ve tried modifying params in validatorMiddleware to add Record <string, number>, using zod with pipe, transform, coerce and nothing worked.
New contributor
dawidzzz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.