Skip to content

Commit 6e2caa7

Browse files
committed
feat: type definitions and documentation for separated type provider.
1 parent 9ac27e0 commit 6e2caa7

File tree

5 files changed

+60
-21
lines changed

5 files changed

+60
-21
lines changed

docs/Guides/Write-Type-Provider.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ For example, `FastifyTypeProviderDefault` will not be assignable to the followin
1919
```ts
2020
export interface NotSubstitutableTypeProvider extends FastifyTypeProvider {
2121
// bad, nothing is assignable to `never` (except for itself)
22-
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
22+
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
23+
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
2324
}
2425
```
2526

2627
Unless changed to:
2728
```ts
2829
export interface SubstitutableTypeProvider extends FastifyTypeProvider {
2930
// good, anything can be assigned to `unknown`
30-
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
31+
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
32+
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
3133
}
3234
```

test/types/register.test-d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance: Serv
7272
}))
7373

7474
// With Type Provider
75-
type TestTypeProvider = { input: 'test', output: 'test' }
75+
type TestTypeProvider = { schema: 'test', validator: 'test', serializer: 'test' }
7676
const serverWithTypeProvider = fastify().withTypeProvider<TestTypeProvider>()
7777
type ServerWithTypeProvider = FastifyInstance<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance, TestTypeProvider>
7878
const testPluginWithTypeProvider: FastifyPluginCallback<TestOptions, RawServerDefault, TestTypeProvider> = function (instance, opts, done) { }

test/types/type-provider.test-d.ts

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ expectAssignable(server.get('/', (req) => expectType<unknown>(req.body)))
2323
// Remapping
2424
// -------------------------------------------------------------------
2525

26-
interface NumberProvider extends FastifyTypeProvider { output: number } // remap all schemas to numbers
26+
interface NumberProvider extends FastifyTypeProvider {
27+
validator: number
28+
serializer: number
29+
} // remap all schemas to numbers
2730

2831
expectAssignable(server.withTypeProvider<NumberProvider>().get(
2932
'/',
@@ -47,7 +50,7 @@ expectAssignable(server.withTypeProvider<NumberProvider>().get(
4750
// Override
4851
// -------------------------------------------------------------------
4952

50-
interface OverriddenProvider extends FastifyTypeProvider { output: 'inferenced' }
53+
interface OverriddenProvider extends FastifyTypeProvider { validator: 'inferenced' }
5154

5255
expectAssignable(server.withTypeProvider<OverriddenProvider>().get<{ Body: 'override' }>(
5356
'/',
@@ -69,7 +72,10 @@ expectAssignable(server.withTypeProvider<OverriddenProvider>().get<{ Body: 'over
6972
// TypeBox
7073
// -------------------------------------------------------------------
7174

72-
interface TypeBoxProvider extends FastifyTypeProvider { output: this['input'] extends TSchema ? Static<this['input']> : unknown }
75+
interface TypeBoxProvider extends FastifyTypeProvider {
76+
validator: this['schema'] extends TSchema ? Static<this['schema']> : unknown
77+
serializer: this['schema'] extends TSchema ? Static<this['schema']> : unknown
78+
}
7379

7480
expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
7581
'/',
@@ -103,7 +109,10 @@ expectAssignable<FastifyInstance>(server.withTypeProvider<TypeBoxProvider>())
103109
// JsonSchemaToTs
104110
// -------------------------------------------------------------------
105111

106-
interface JsonSchemaToTsProvider extends FastifyTypeProvider { output: this['input'] extends JSONSchema ? FromSchema<this['input']> : unknown }
112+
interface JsonSchemaToTsProvider extends FastifyTypeProvider {
113+
validator: this['schema'] extends JSONSchema ? FromSchema<this['schema']> : unknown
114+
serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema']> : unknown
115+
}
107116

108117
// explicitly setting schema `as const`
109118

@@ -1003,7 +1012,7 @@ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: b
10031012
// FastifyPlugin: Auxiliary
10041013
// -------------------------------------------------------------------
10051014

1006-
interface AuxiliaryPluginProvider extends FastifyTypeProvider { output: 'plugin-auxiliary' }
1015+
interface AuxiliaryPluginProvider extends FastifyTypeProvider { validator: 'plugin-auxiliary' }
10071016

10081017
// Auxiliary plugins may have varying server types per application. Recommendation would be to explicitly remap instance provider context within plugin if required.
10091018
function plugin<T extends FastifyInstance> (instance: T) {
@@ -1032,7 +1041,7 @@ expectAssignable(server.withTypeProvider<AuxiliaryPluginProvider>().register(plu
10321041
// Handlers: Inline
10331042
// -------------------------------------------------------------------
10341043

1035-
interface InlineHandlerProvider extends FastifyTypeProvider { output: 'handler-inline' }
1044+
interface InlineHandlerProvider extends FastifyTypeProvider { validator: 'handler-inline' }
10361045

10371046
// Inline handlers should infer for the request parameters (non-shared)
10381047
expectAssignable(server.withTypeProvider<InlineHandlerProvider>().get(
@@ -1052,7 +1061,7 @@ expectAssignable(server.withTypeProvider<InlineHandlerProvider>().get(
10521061
// Handlers: Auxiliary
10531062
// -------------------------------------------------------------------
10541063

1055-
interface AuxiliaryHandlerProvider extends FastifyTypeProvider { output: 'handler-auxiliary' }
1064+
interface AuxiliaryHandlerProvider extends FastifyTypeProvider { validator: 'handler-auxiliary' }
10561065

10571066
// Auxiliary handlers are likely shared for multiple routes and thus should infer as unknown due to potential varying parameters
10581067
function auxiliaryHandler (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction): void {
@@ -1069,3 +1078,29 @@ expectAssignable(server.withTypeProvider<AuxiliaryHandlerProvider>().get(
10691078
expectType<'handler-auxiliary'>(req.body)
10701079
}
10711080
))
1081+
1082+
// -------------------------------------------------------------------
1083+
// Separate Providers
1084+
// -------------------------------------------------------------------
1085+
1086+
interface SeparateProvider extends FastifyTypeProvider {
1087+
validator: string
1088+
serializer: Date
1089+
}
1090+
1091+
expectAssignable(server.withTypeProvider<SeparateProvider>().get(
1092+
'/',
1093+
{
1094+
schema: {
1095+
body: null,
1096+
response: {
1097+
200: { type: 'string' }
1098+
}
1099+
}
1100+
},
1101+
(req, res) => {
1102+
expectType<string>(req.body)
1103+
1104+
res.send(new Date())
1105+
}
1106+
))

types/reply.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FastifyBaseLogger } from './logger'
55
import { FastifyRequest } from './request'
66
import { RouteGenericInterface } from './route'
77
import { FastifySchema } from './schema'
8-
import { FastifyReplyType, FastifyTypeProvider, FastifyTypeProviderDefault, ResolveFastifyReplyType, CallTypeProvider } from './type-provider'
8+
import { CallSerializerTypeProvider, FastifyReplyType, FastifyTypeProvider, FastifyTypeProviderDefault, ResolveFastifyReplyType } from './type-provider'
99
import { CodeToReplyKey, ContextConfigDefault, HttpKeys, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, ReplyDefault, ReplyKeysToCodes, HttpHeader } from './utils'
1010

1111
export interface ReplyGenericInterface {
@@ -24,7 +24,7 @@ export type ResolveReplyTypeWithRouteGeneric<RouteGenericReply, Code extends Rep
2424
SchemaCompiler extends FastifySchema = FastifySchema,
2525
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault> =
2626
Code extends keyof SchemaCompiler['response'] ?
27-
CallTypeProvider<TypeProvider, SchemaCompiler['response'][Code]> :
27+
CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][Code]> :
2828
ResolveFastifyReplyType<TypeProvider, SchemaCompiler, { Reply: ReplyTypeConstrainer<RouteGenericReply, Code> }>
2929
/**
3030
* FastifyReply is an instance of the standard http or http2 reply types.

types/type-provider.d.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import { RecordKeysToLowercase } from './utils'
77
// -----------------------------------------------------------------------------------------------
88

99
export interface FastifyTypeProvider {
10-
readonly input: unknown,
11-
readonly output: unknown,
10+
readonly schema: unknown,
11+
readonly validator: unknown,
12+
readonly serializer: unknown,
1213
}
1314

1415
// eslint-disable-next-line @typescript-eslint/no-empty-interface
1516
export interface FastifyTypeProviderDefault extends FastifyTypeProvider {}
1617

17-
export type CallTypeProvider<F extends FastifyTypeProvider, I> = (F & { input: I })['output']
18+
export type CallValidatorTypeProvider<F extends FastifyTypeProvider, S> = (F & { schema: S })['validator']
19+
export type CallSerializerTypeProvider<F extends FastifyTypeProvider, S> = (F & { schema: S })['serializer']
1820

1921
// -----------------------------------------------------------------------------------------------
2022
// FastifyRequestType
@@ -32,13 +34,13 @@ type KeysOf<T> = T extends any ? keyof T : never
3234

3335
// Resolves Request types either from generic argument or Type Provider.
3436
type ResolveRequestParams<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
35-
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
37+
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
3638
type ResolveRequestQuerystring<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
37-
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
39+
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
3840
type ResolveRequestHeaders<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
39-
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
41+
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
4042
type ResolveRequestBody<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
41-
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
43+
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
4244

4345
// The target request type. This type is inferenced on fastify 'requests' via generic argument assignment
4446
export interface FastifyRequestType<Params = unknown, Querystring = unknown, Headers = unknown, Body = unknown> {
@@ -63,8 +65,8 @@ export interface ResolveFastifyRequestType<TypeProvider extends FastifyTypeProvi
6365
// Resolves the Reply type by taking a union of response status codes and content-types
6466
type ResolveReplyFromSchemaCompiler<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema> = {
6567
[K1 in keyof SchemaCompiler['response']]: SchemaCompiler['response'][K1] extends { content: { [keyof: string]: { schema: unknown } } } ? ({
66-
[K2 in keyof SchemaCompiler['response'][K1]['content']]: CallTypeProvider<TypeProvider, SchemaCompiler['response'][K1]['content'][K2]['schema']>
67-
} extends infer Result ? Result[keyof Result] : unknown) : CallTypeProvider<TypeProvider, SchemaCompiler['response'][K1]>
68+
[K2 in keyof SchemaCompiler['response'][K1]['content']]: CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][K1]['content'][K2]['schema']>
69+
} extends infer Result ? Result[keyof Result] : unknown) : CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][K1]>
6870
} extends infer Result ? Result[keyof Result] : unknown;
6971

7072
// The target reply type. This type is inferenced on fastify 'replies' via generic argument assignment

0 commit comments

Comments
 (0)