import { expectAssignable, expectError, expectNotAssignable, expectNotDeprecated, expectType } from 'tsd' import fastify, { FastifyBaseLogger, FastifyBodyParser, FastifyError, FastifyInstance, FastifyRouterOptions, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault, RouteGenericInterface } from '../../fastify' import { HookHandlerDoneFunction } from '../../types/hooks' import { FastifyReply } from '../../types/reply' import { FastifyRequest } from '../../types/request' import { FastifySchemaControllerOptions, FastifySchemaCompiler, FastifySerializerCompiler } from '../../types/schema' import { AddressInfo } from 'node:net' import { Bindings, ChildLoggerOptions } from '../../types/logger' import { Config as FindMyWayConfig, ConstraintStrategy } from 'find-my-way' import { FindMyWayVersion } from '../../types/instance' const server = fastify() expectAssignable(server.addSchema({ type: 'null' })) expectAssignable(server.addSchema({ schemaId: 'id' })) expectAssignable(server.addSchema({ schemas: [] })) expectType(server.pluginName) expectType>(server.getSchemas()) expectType(server.addresses()) expectType(server.getSchema('SchemaId')) expectType(server.printRoutes()) expectType(server.printPlugins()) expectType(server.listeningOrigin) expectType(server.supportedMethods) expectAssignable( server.setErrorHandler(function (error, request, reply) { expectType(error) expectAssignable(this) }) ) expectAssignable( server.setErrorHandler(function (error, request, reply) { expectType(error) }) ) expectAssignable( server.setGenReqId(function (req) { expectType(req) return 'foo' }) ) function fastifySetGenReqId (req: RawRequestDefaultExpression) { return 'foo' } server.setGenReqId(fastifySetGenReqId) function fastifyErrorHandler (this: FastifyInstance, error: FastifyError) {} server.setErrorHandler(fastifyErrorHandler) async function asyncFastifyErrorHandler (this: FastifyInstance, error: FastifyError) {} server.setErrorHandler(asyncFastifyErrorHandler) function nodeJSErrorHandler (error: NodeJS.ErrnoException) { if (error) { throw error } } server.setErrorHandler(nodeJSErrorHandler) function asyncNodeJSErrorHandler (error: NodeJS.ErrnoException) { if (error) { throw error } } server.setErrorHandler(asyncNodeJSErrorHandler) class CustomError extends Error { private __brand: any } interface ReplyPayload { Reply: { test: boolean; }; } // typed sync error handler server.setErrorHandler((error, request, reply) => { expectType(error) expectType<((...args: [payload: ReplyPayload['Reply']]) => FastifyReply, RawReplyDefaultExpression>)>(reply.send) }) // typed async error handler send server.setErrorHandler(async (error, request, reply) => { expectType(error) expectType<((...args: [payload: ReplyPayload['Reply']]) => FastifyReply, RawReplyDefaultExpression>)>(reply.send) }) // typed async error handler return server.setErrorHandler(async (error, request, reply) => { expectType(error) return { test: true } }) // typed sync error handler send error expectError(server.setErrorHandler((error, request, reply) => { expectType(error) reply.send({ test: 'foo' }) })) // typed sync error handler return error server.setErrorHandler((error, request, reply) => { expectType(error) return { test: 'foo' } }) // typed async error handler send error expectError(server.setErrorHandler(async (error, request, reply) => { expectType(error) reply.send({ test: 'foo' }) })) // typed async error handler return error server.setErrorHandler(async (error, request, reply) => { expectType(error) return { test: 'foo' } }) function notFoundHandler (request: FastifyRequest, reply: FastifyReply) {} async function notFoundAsyncHandler (request: FastifyRequest, reply: FastifyReply) {} function notFoundpreHandlerHandler ( request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction ) { done() } async function notFoundpreHandlerAsyncHandler ( request: FastifyRequest, reply: FastifyReply ) {} function notFoundpreValidationHandler ( request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction ) { done() } async function notFoundpreValidationAsyncHandler ( request: FastifyRequest, reply: FastifyReply ) {} server.setNotFoundHandler(notFoundHandler) server.setNotFoundHandler({ preHandler: notFoundpreHandlerHandler }, notFoundHandler) server.setNotFoundHandler({ preHandler: notFoundpreHandlerAsyncHandler }, notFoundHandler) server.setNotFoundHandler({ preValidation: notFoundpreValidationHandler }, notFoundHandler) server.setNotFoundHandler({ preValidation: notFoundpreValidationAsyncHandler }, notFoundHandler) server.setNotFoundHandler( { preHandler: notFoundpreHandlerHandler, preValidation: notFoundpreValidationHandler }, notFoundHandler ) server.setNotFoundHandler(notFoundAsyncHandler) server.setNotFoundHandler({ preHandler: notFoundpreHandlerHandler }, notFoundAsyncHandler) server.setNotFoundHandler({ preHandler: notFoundpreHandlerAsyncHandler }, notFoundAsyncHandler) server.setNotFoundHandler({ preValidation: notFoundpreValidationHandler }, notFoundAsyncHandler) server.setNotFoundHandler({ preValidation: notFoundpreValidationAsyncHandler }, notFoundAsyncHandler) server.setNotFoundHandler( { preHandler: notFoundpreHandlerHandler, preValidation: notFoundpreValidationHandler }, notFoundAsyncHandler ) server.setNotFoundHandler(function (_, reply) { return reply.send('') }) server.setSchemaController({ bucket: (parentSchemas: unknown) => { return { add (schema: unknown) { expectType(schema) expectType(server.addSchema({ type: 'null' })) return server.addSchema({ type: 'null' }) }, getSchema (schemaId: string) { expectType(schemaId) return server.getSchema('SchemaId') }, getSchemas () { expectType>(server.getSchemas()) return server.getSchemas() } } } }) function invalidSchemaController (schemaControllerOptions: FastifySchemaControllerOptions) {} expectError(server.setSchemaController(invalidSchemaController)) server.setReplySerializer(function (payload, statusCode) { expectType(payload) expectType(statusCode) return 'serialized' }) function invalidReplySerializer (payload: number, statusCode: string) {} expectError(server.setReplySerializer(invalidReplySerializer)) function serializerWithInvalidReturn (payload: unknown, statusCode: number) {} expectError(server.setReplySerializer(serializerWithInvalidReturn)) function invalidSchemaErrorFormatter (err: Error) { if (err) { throw err } } expectError(server.setSchemaErrorFormatter(invalidSchemaErrorFormatter)) expectType(server.addHttpMethod('SEARCH', { hasBody: true })) // test listen opts objects expectAssignable>(server.listen()) expectAssignable>(server.listen({ port: 3000 })) expectAssignable>(server.listen({ port: 3000, listenTextResolver: (address) => { return `address: ${address}` } })) expectAssignable>(server.listen({ port: 3000, host: '0.0.0.0' })) expectAssignable>(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 })) expectAssignable>(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42, exclusive: true })) expectAssignable>(server.listen({ port: 3000, host: '::/0', ipv6Only: true })) expectAssignable(server.listen(() => {})) expectAssignable(server.listen({ port: 3000 }, () => {})) expectAssignable(server.listen({ port: 3000, listenTextResolver: (address) => { return `address: ${address}` } }, () => {})) expectAssignable(server.listen({ port: 3000, host: '0.0.0.0' }, () => {})) expectAssignable(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 }, () => {})) expectAssignable(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42, exclusive: true }, () => {})) expectAssignable(server.listen({ port: 3000, host: '::/0', ipv6Only: true }, () => {})) // test listen opts objects Typescript deprecation exclusion expectNotDeprecated(server.listen()) expectNotDeprecated(server.listen({ port: 3000 })) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0' })) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 })) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42, exclusive: true })) expectNotDeprecated(server.listen({ port: 3000, host: '::/0', ipv6Only: true })) expectNotDeprecated(server.listen(() => {})) expectNotDeprecated(server.listen({ port: 3000 }, () => {})) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0' }, () => {})) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 }, () => {})) expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42, exclusive: true }, () => {})) expectNotDeprecated(server.listen({ port: 3000, host: '::/0', ipv6Only: true }, () => {})) // test after method expectAssignable(server.after()) expectAssignable(server.after((err) => { expectType(err) })) // test ready method expectAssignable(server.ready()) expectAssignable(server.ready((err) => { expectType(err) })) expectAssignable(server.ready(async (err) => { expectType(err) })) expectAssignable[0]>(async (err) => { expectType(err) }) expectAssignable(server.routing({} as RawRequestDefaultExpression, {} as RawReplyDefaultExpression)) expectType(fastify().get('/', { handler: () => {}, errorHandler: (error, request, reply) => { expectAssignable(error) expectAssignable(request) expectAssignable<{ contextKey: string }>(request.routeOptions.config) expectAssignable(reply) expectAssignable(server.errorHandler(error, request, reply)) } })) expectType(fastify().get('/', { handler: () => {}, childLoggerFactory: (logger, bindings, opts, req) => { expectAssignable(server.childLoggerFactory(logger, bindings, opts, req)) return server.childLoggerFactory(logger, bindings, opts, req) } })) expectAssignable( server.setChildLoggerFactory(function (logger, bindings, opts, req) { expectType(logger) expectType(bindings) expectType(opts) expectType(req) expectAssignable(this) return logger.child(bindings, opts) }) ) expectAssignable( server.setErrorHandler(function (error, request, reply) { expectType(error) }) ) function childLoggerFactory ( this: FastifyInstance, logger: FastifyBaseLogger, bindings: Bindings, opts: ChildLoggerOptions, req: RawRequestDefaultExpression ) { return logger.child(bindings, opts) } server.setChildLoggerFactory(childLoggerFactory) server.setChildLoggerFactory(server.childLoggerFactory) type InitialConfig = Readonly<{ connectionTimeout?: number, keepAliveTimeout?: number, bodyLimit?: number, caseSensitive?: boolean, allowUnsafeRegex?: boolean, forceCloseConnections?: boolean, http2?: boolean, https?: boolean | Readonly<{ allowHTTP1: boolean }>, ignoreTrailingSlash?: boolean, ignoreDuplicateSlashes?: boolean, disableRequestLogging?: boolean | ((req: FastifyRequest) => boolean), maxParamLength?: number, onProtoPoisoning?: 'error' | 'remove' | 'ignore', onConstructorPoisoning?: 'error' | 'remove' | 'ignore', pluginTimeout?: number, requestIdHeader?: string | false, requestIdLogLabel?: string, http2SessionTimeout?: number, useSemicolonDelimiter?: boolean, routerOptions?: FastifyRouterOptions }> expectType(fastify().initialConfig) const routerOptionsForFindMyWay = {} as FastifyRouterOptions expectAssignable>>(routerOptionsForFindMyWay) fastify({ routerOptions: { defaultRoute: (req, res) => { expectType>(req) expectType>(res) expectNotAssignable(res) res.end('foo') }, onBadUrl: (path, req, res) => { expectType(path) expectType>(req) expectType>(res) expectNotAssignable(res) res.end('foo') } } }) expectType>(server.defaultTextParser) expectType>(server.getDefaultJsonParser('ignore', 'error')) expectType(server.printRoutes({ includeHooks: true, commonPrefix: false, includeMeta: true })) expectType(server.printRoutes({ includeMeta: ['key1', Symbol('key2')] })) expectType(server.printRoutes({ method: 'GET' })) expectType(server.printRoutes()) server.decorate<(x: string) => void>('test', function (x: string): void { expectType(this) }) server.decorate('test', function (x: string): void { expectType(this) }) server.decorate('test', { getter () { expectType(this) return 'foo' } }) server.decorate('test', { getter () { expectType(this) return 'foo' }, setter (x) { expectType(x) expectType(this) } }) server.decorate('test') server.decorate('test', null, ['foo']) server.decorateRequest<(x: string, y: number) => void>('test', function (x: string, y: number): void { expectType(this) }) server.decorateRequest('test', function (x: string, y: number): void { expectType(this) }) server.decorateRequest('test') server.decorateRequest('test', null, ['foo']) server.decorateReply<(x: string) => void>('test', function (x: string): void { expectType(this) }) server.decorateReply('test', function (x: string): void { expectType(this) }) server.decorateReply('test') server.decorateReply('test', null, ['foo']) expectError(server.decorate('test', true)) expectError(server.decorate<(myNumber: number) => number>('test', function (myNumber: number): string { return '' })) expectError(server.decorate('test', { getter () { return true } })) expectError(server.decorate('test', { setter (x) {} })) declare module '../../fastify' { interface FastifyInstance { typedTestProperty: boolean typedTestPropertyGetterSetter: string typedTestMethod (x: string): string } interface FastifyRequest { typedTestRequestProperty: boolean typedTestRequestPropertyGetterSetter: string typedTestRequestMethod (x: string): string } interface FastifyReply { typedTestReplyProperty: boolean typedTestReplyPropertyGetterSetter: string typedTestReplyMethod (x: string): string } } server.decorate('typedTestProperty', false) server.decorate('typedTestProperty', { getter () { return false } }) server.decorate('typedTestProperty', { getter (): boolean { return true }, setter (x) { expectType(x) expectType(this) } }) server.decorate('typedTestProperty') server.decorate('typedTestProperty', null, ['foo']) expectError(server.decorate('typedTestProperty', null)) expectError(server.decorate('typedTestProperty', 'foo')) expectError(server.decorate('typedTestProperty', { getter () { return 'foo' } })) server.decorate('typedTestMethod', function (x) { expectType(x) expectType(this) return 'foo' }) server.decorate('typedTestMethod', x => x) expectError(server.decorate('typedTestMethod', function (x: boolean) { return 'foo' })) expectError(server.decorate('typedTestMethod', function (x) { return true })) expectError(server.decorate('typedTestMethod', async function (x) { return 'foo' })) server.decorateRequest('typedTestRequestProperty', false) server.decorateRequest('typedTestRequestProperty', { getter () { return false } }) server.decorateRequest('typedTestRequestProperty', { getter (): boolean { return true }, setter (x) { expectType(x) expectType(this) } }) server.decorateRequest('typedTestRequestProperty') server.decorateRequest('typedTestRequestProperty', null, ['foo']) expectError(server.decorateRequest('typedTestRequestProperty', null)) expectError(server.decorateRequest('typedTestRequestProperty', 'foo')) expectError(server.decorateRequest('typedTestRequestProperty', { getter () { return 'foo' } })) server.decorateRequest('typedTestRequestMethod', function (x) { expectType(x) expectType(this) return 'foo' }) server.decorateRequest('typedTestRequestMethod', x => x) expectError(server.decorateRequest('typedTestRequestMethod', function (x: boolean) { return 'foo' })) expectError(server.decorateRequest('typedTestRequestMethod', function (x) { return true })) expectError(server.decorateRequest('typedTestRequestMethod', async function (x) { return 'foo' })) server.decorateReply('typedTestReplyProperty', false) server.decorateReply('typedTestReplyProperty', { getter () { return false } }) server.decorateReply('typedTestReplyProperty', { getter (): boolean { return true }, setter (x) { expectType(x) expectType(this) } }) server.decorateReply('typedTestReplyProperty') server.decorateReply('typedTestReplyProperty', null, ['foo']) expectError(server.decorateReply('typedTestReplyProperty', null)) expectError(server.decorateReply('typedTestReplyProperty', 'foo')) expectError(server.decorateReply('typedTestReplyProperty', { getter () { return 'foo' } })) server.decorateReply('typedTestReplyMethod', function (x) { expectType(x) expectType(this) return 'foo' }) server.decorateReply('typedTestReplyMethod', x => x) expectError(server.decorateReply('typedTestReplyMethod', function (x: boolean) { return 'foo' })) expectError(server.decorateReply('typedTestReplyMethod', function (x) { return true })) expectError(server.decorateReply('typedTestReplyMethod', async function (x) { return 'foo' })) const foo = server.getDecorator('foo') expectType(foo) const versionConstraintStrategy: ConstraintStrategy> = { name: 'version', storage: () => ({ get: () => () => {}, set: () => { }, del: () => { }, empty: () => { } }), validate () {}, deriveConstraint: () => 'foo' } expectType(server.addConstraintStrategy(versionConstraintStrategy)) expectType(server.hasConstraintStrategy(versionConstraintStrategy.name)) expectType | undefined>(server.validatorCompiler) expectType | undefined>(server.serializerCompiler)