-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Invalid return type in route handler with generic reply type with status codes #6020
Copy link
Copy link
Closed
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Fastify version
5.x.x
Plugin version
No response
Node.js version
Any
Operating system
Linux
Operating system version (i.e. 20.04, 11.3, 10)
Any
Description
import Fastify from 'fastify'
const fastify = Fastify()
fastify.get<{
Reply: {
200: { msg: string }
400: { error: string }
}
}>('/', async (request, reply) => {
reply.code(200).send({ msg: 'works' })
reply.code(400).send({ error: 'works' })
return { msg: `valid but typescript would complain` }
// return {
// 200: { msg: `invalid but typescript wouldn't complain` },
// 400: { error: `invalid` }
// }
})Got TypeScript error:
No overload matches this call.
Overload 1 of 3, '(path: string, handler: RouteHandlerMethod<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>): FastifyInstance<...>', gave the following error.
Argument of type '(this: FastifyInstance<...>, request: FastifyRequest<{ Reply: { 200: { msg: string; }; 400: { error: string; }; }; }, Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ... 4 more ..., ResolveFastifyRequestType<...>>, reply: FastifyReply<...>) => Promise<...>' is not assignable to parameter of type 'RouteHandlerMethod<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>'.
Type 'Promise<{ msg: string; }>' is not assignable to type 'void | { 200: { msg: string; }; 400: { error: string; }; } | Promise<void | { 200: { msg: string; }; 400: { error: string; }; }>'.
Type 'Promise<{ msg: string; }>' is not assignable to type 'Promise<void | { 200: { msg: string; }; 400: { error: string; }; }>'.
Type '{ msg: string; }' is not assignable to type 'void | { 200: { msg: string; }; 400: { error: string; }; }'.
Overload 2 of 3, '(path: string, opts: RouteShorthandOptionsWithHandler<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>): FastifyInstance<...>', gave the following error.
Argument of type '(this: FastifyInstance<...>, request: FastifyRequest<{ Reply: { 200: { msg: string; }; 400: { error: string; }; }; }, Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ... 4 more ..., ResolveFastifyRequestType<...>>, reply: FastifyReply<...>) => Promise<...>' is not assignable to parameter of type 'RouteShorthandOptionsWithHandler<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>'.ts(2769)
#5704 mentioned this issue but the description wasn't clear enough so that's might be why it's closed and the issue remains existing.
Link to code that reproduces the bug
Code above
Expected Behavior
return { msg: 'valid' } should be valid.
Should I send a PR to fix this? The following tests (to be added) should pass:
// -------------------------------------------------------------------
// Reply Type Return Override (Different Status Codes)
// -------------------------------------------------------------------
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{
Reply: {
200: string | { msg: string }
400: { error: string }
'5xx': { serverError: string }
}
}>(
'/',
{
schema: {
response: {
200: { type: 'string' },
400: { type: 'number' },
500: { type: 'object', properties: { error: { type: 'string' } } }
} as const
}
},
async (_, res) => {
const option = 1 as 1 | 2 | 3 | 4
switch (option) {
case 1: return 'hello'
case 2: return { msg: 'hello' }
case 3: return { error: 'error' }
case 4: return { serverError: 'error' }
}
}
))
// -------------------------------------------------------------------
// Reply Type Return Override: Non Assignable (Different Status Codes)
// -------------------------------------------------------------------
expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get<{
Reply: {
200: string | { msg: string }
400: { error: string }
'5xx': { serverError: string }
}
}>(
'/',
{
schema: {
response: {
200: { type: 'string' },
400: { type: 'number' },
500: { type: 'object', properties: { error: { type: 'string' } } }
} as const
}
},
async (_, res) => {
return true
}
))Or if only Reply[200] should be returned:
// -------------------------------------------------------------------
// Reply Type Return Override (Different Status Codes)
// -------------------------------------------------------------------
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{
Reply: {
200: string | { msg: string }
400: { error: string }
'5xx': { serverError: string }
}
}>(
'/',
{
schema: {
response: {
200: { type: 'string' },
400: { type: 'number' },
500: { type: 'object', properties: { error: { type: 'string' } } }
} as const
}
},
async (_, res) => {
const option = 1 as 1 | 2
switch (option) {
case 1: return 'hello'
case 2: return { msg: 'hello' }
}
}
))
// -------------------------------------------------------------------
// Reply Type Return Override: Non Assignable (Different Status Codes)
// -------------------------------------------------------------------
expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get<{
Reply: {
200: string | { msg: string }
400: { error: string }
'5xx': { serverError: string }
}
}>(
'/',
{
schema: {
response: {
200: { type: 'string' },
400: { type: 'number' },
500: { type: 'object', properties: { error: { type: 'string' } } }
} as const
}
},
async (_, res) => {
return { error: 'error' }
}
))Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels