Skip to content

Commit

Permalink
Use a union-aware keyof operator (#4076)
Browse files Browse the repository at this point in the history
  • Loading branch information
A5rocks committed Jun 24, 2022
1 parent 7e6dca0 commit 4d1fb5f
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 8 deletions.
10 changes: 7 additions & 3 deletions test/types/request.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ interface RequestData extends RequestGenericInterface {
type Handler = RouteHandler<RequestData>

type CustomRequest = FastifyRequest<{
Body: RequestBody;
Body: RequestBody | undefined;
Querystring: RequestQuerystring;
Params: RequestParams;
Headers: RequestHeaders;
Expand Down Expand Up @@ -104,11 +104,15 @@ const postHandler: Handler = function (request) {
}

function putHandler (request: CustomRequest, reply: FastifyReply) {
expectType<RequestBody>(request.body)
expectType<RequestBody | undefined>(request.body)
expectType<RequestParams>(request.params)
expectType<RequestHeaders & RawRequestDefaultExpression['headers']>(request.headers)
expectType<RequestQuerystring>(request.query)
expectType<string>(request.body.content)
if (typeof request.body === 'undefined') {
expectType<undefined>(request.body)
} else {
expectType<string>(request.body.content)
}
expectType<string>(request.query.from)
expectType<number>(request.params.id)
expectType<string>(request.headers['x-foobar'])
Expand Down
17 changes: 12 additions & 5 deletions types/type-provider.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,24 @@ export type CallTypeProvider<F extends FastifyTypeProvider, I> = (F & { input: I
// -----------------------------------------------------------------------------------------------

// Used to map undefined SchemaCompiler properties to unknown
type UndefinedToUnknown<T> = T extends undefined ? unknown : T
// Without brackets, UndefinedToUnknown<undefined | null> => unknown
type UndefinedToUnknown<T> = [T] extends [undefined] ? unknown : T

// union-aware keyof operator
// keyof ({ a: number} | { b: number}) => never
// KeysOf<{a: number} | {b: number}> => "a" | "b"
// this exists to allow users to override faulty type-provider logic.
type KeysOf<T> = T extends any ? keyof T : never

// Resolves Request types either from generic argument or Type Provider.
type ResolveRequestParams<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<keyof RouteGeneric['Params'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
type ResolveRequestQuerystring<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<keyof RouteGeneric['Querystring'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
type ResolveRequestHeaders<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<keyof RouteGeneric['Headers'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
type ResolveRequestBody<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<keyof RouteGeneric['Body'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>

// The target request type. This type is inferenced on fastify 'requests' via generic argument assignment
export interface FastifyRequestType<Params = unknown, Querystring = unknown, Headers = unknown, Body = unknown> {
Expand Down

0 comments on commit 4d1fb5f

Please sign in to comment.