Skip to content

Commit f948814

Browse files
committedOct 16, 2020
fix: use TS type inference for hooks
1 parent 1562086 commit f948814

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed
 

‎test/types/hooks.test-d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ server.addHook('onRequest', (request, reply, done) => {
2323
expectType<void>(done(new Error()))
2424
})
2525

26+
expectError(server.addHook('onRequest', async (request, reply, done) => {}))
27+
28+
server.addHook('onRequest', async (request, reply) => {
29+
expectType<FastifyRequest>(request)
30+
expectType<FastifyReply>(reply)
31+
})
32+
2633
server.addHook('preParsing', (request, reply, payload, done) => {
2734
expectType<FastifyRequest>(request)
2835
expectType<FastifyReply>(reply)

‎types/callback-or-promise.d.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Common type for all functions that may use callback as last argument or return promise instead
2+
// T - function to infer type from
3+
// Args - hook Args
4+
// DoneFn - hook callback
5+
export type CallbackOrPromise<T, Args extends any[], DoneFn> =
6+
// Ensure that TS use function as T
7+
T extends (...args: [...Args, infer U]) => any
8+
// Check whether last argument of given function is may be DoneFn
9+
? DoneFn extends U
10+
// If yes we check whether return type is promise or not
11+
? ReturnType<T> extends Promise<any>
12+
// If return type is promise we have to check is last arguments unknown
13+
? U extends unknown
14+
// If it unknown then we return corresponding signature
15+
? (...args: Args) => Promise<void>
16+
// If it known (for example has any type) we return never to prevent this case
17+
: never
18+
// Else we return sugnature with DoneFn as last argument
19+
: (...args: [...Args, DoneFn]) => void
20+
: ReturnType<T> extends Promise<any> ? (...args: Args) => Promise<void> : never
21+
// If TS pass non function to as T then we just return T to prevent errors
22+
: T

‎types/hooks.d.ts

+11-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/class-name-casing */
22

33
import { Readable } from 'stream'
4+
import { CallbackOrPromise } from './callback-or-promise'
45
import { FastifyInstance } from './instance'
56
import { RouteOptions, RouteGenericInterface } from './route'
67
import { RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, ContextConfigDefault } from './utils'
@@ -21,23 +22,20 @@ interface RequestPayload extends Readable {
2122
* `onRequest` is the first hook to be executed in the request lifecycle. There was no previous hook, the next hook will be `preParsing`.
2223
* Notice: in the `onRequest` hook, request.body will always be null, because the body parsing happens before the `preHandler` hook.
2324
*/
24-
export interface onRequestHookHandler<
25+
export type onRequestHookHandler<
2526
RawServer extends RawServerBase = RawServerDefault,
2627
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
2728
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
2829
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
29-
ContextConfig = ContextConfigDefault
30-
> {
31-
(
32-
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
33-
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
34-
done: HookHandlerDoneFunction
35-
): void;
36-
(
37-
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
38-
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
39-
): Promise<unknown>;
40-
}
30+
ContextConfig = ContextConfigDefault,
31+
T extends (...args: any[]) => void = (...args: any[]) => void
32+
> = CallbackOrPromise<
33+
T,
34+
[
35+
FastifyRequest<RouteGeneric, RawServer, RawRequest>,
36+
FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
37+
],
38+
HookHandlerDoneFunction>
4139

4240
/**
4341
* `preParsing` is the second hook to be executed in the request lifecycle. The previous hook was `onRequest`, the next hook will be `preValidation`.

‎types/instance.d.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ export interface FastifyInstance<
9090
*/
9191
addHook<
9292
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
93-
ContextConfig = ContextConfigDefault
93+
ContextConfig = ContextConfigDefault,
94+
T extends (...args: any[]) => void = (...args: any[]) => void
9495
>(
9596
name: 'onRequest',
96-
hook: onRequestHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
97+
hook: onRequestHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, T>
9798
): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
9899

99100
/**

0 commit comments

Comments
 (0)
Please sign in to comment.