Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix inferring the correct fn type #218

Merged
merged 6 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions types/example-async.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FastifyPluginAsync } from "fastify";

type FastifyExampleAsync = FastifyPluginAsync<fastifyExampleAsync.FastifyExampleAsyncOptions>;

declare namespace fastifyExampleAsync {

export interface FastifyExampleAsyncOptions {
foo?: 'bar'
}

export interface FastifyExampleAsyncPluginOptions extends FastifyExampleAsyncOptions {
}
export const fastifyExampleAsync: FastifyExampleAsync
export { fastifyExampleAsync as default }
}

declare function fastifyExampleAsync(...params: Parameters<FastifyExampleAsync>): ReturnType<FastifyExampleAsync>

export default fastifyExampleAsync
Uzlopak marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 19 additions & 0 deletions types/example-callback.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FastifyPluginCallback } from "fastify";

type FastifyExampleCallback = FastifyPluginCallback<fastifyExampleCallback.FastifyExampleCallbackOptions>;

declare namespace fastifyExampleCallback {

export interface FastifyExampleCallbackOptions {
foo?: 'bar'
}

export interface FastifyExampleCallbackPluginOptions extends FastifyExampleCallbackOptions {
}
export const fastifyExampleCallback: FastifyExampleCallback
export { fastifyExampleCallback as default }
}

declare function fastifyExampleCallback(...params: Parameters<FastifyExampleCallback>): ReturnType<FastifyExampleCallback>

export default fastifyExampleCallback
42 changes: 10 additions & 32 deletions types/plugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
RawServerDefault,
FastifyTypeProvider,
FastifyTypeProviderDefault,
FastifyBaseLogger,
} from 'fastify'
import { IncomingMessage, Server, ServerResponse } from 'http'

type FastifyPlugin = typeof fastifyPlugin

Expand Down Expand Up @@ -45,40 +47,16 @@ declare namespace fastifyPlugin {
* @param fn Fastify plugin function
* @param options Optional plugin options
*/
declare function fastifyPlugin<
Options extends FastifyPluginOptions,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
>(
fn: FastifyPluginAsync<Options, RawServer, TypeProvider>,
options?: fastifyPlugin.PluginMetadata
): FastifyPluginAsync<Options, RawServer, TypeProvider>;

declare function fastifyPlugin<
Options extends FastifyPluginOptions,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
>(
fn: FastifyPluginAsync<Options, RawServer, TypeProvider>,
options?: string
): FastifyPluginAsync<Options, RawServer, TypeProvider>;

declare function fastifyPlugin<
Options extends FastifyPluginOptions,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
>(
fn: FastifyPluginCallback<Options, RawServer, TypeProvider>,
options?: fastifyPlugin.PluginMetadata
): FastifyPluginCallback<Options, RawServer, TypeProvider>;

declare function fastifyPlugin<
Options extends FastifyPluginOptions,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
Options extends FastifyPluginOptions = Record<never, never>,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger,
Fn extends FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> | FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> = FastifyPluginCallback<Options, RawServer, TypeProvider, Logger>
>(
fn: FastifyPluginCallback<Options>,
options?: string
): FastifyPluginCallback<Options>;
fn: Fn extends unknown ? Fn extends (...args: any) => Promise<any> ? FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> : FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> : Fn,
options?: fastifyPlugin.PluginMetadata | string
): Fn;

export = fastifyPlugin
124 changes: 94 additions & 30 deletions types/plugin.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import fastifyPlugin from '..';
import fastify, { FastifyPluginCallback, FastifyPluginAsync, FastifyError, FastifyInstance, FastifyPluginOptions } from 'fastify';
import { expectAssignable } from 'tsd'
import fastify, { FastifyPluginCallback, FastifyPluginAsync, FastifyError, FastifyInstance, FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger } from 'fastify';
import { expectAssignable, expectError, expectNotType, expectType } from 'tsd'
import { Server } from "node:https"
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox"
import fastifyExampleCallback from './example-callback.test-d';
import fastifyExampleAsync from './example-async.test-d';

interface Options {
foo: string
Expand All @@ -13,79 +15,81 @@ const testSymbol = Symbol('foobar')
// Callback

const pluginCallback: FastifyPluginCallback = (fastify, options, next) => { }
expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallback))
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback))

const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }
expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallbackWithTypes))
expectNotType<any>(fastifyPlugin(pluginCallbackWithTypes))

expectAssignable<FastifyPluginCallback>(fastifyPlugin((fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }))
expectNotType<any>(fastifyPlugin((fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }))

expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallback, '' ))
expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallback, {
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, ''))
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, {
fastify: '',
name: '',
decorators: {
fastify: [ '', testSymbol ],
reply: [ '', testSymbol ],
request: [ '', testSymbol ]
fastify: ['', testSymbol],
reply: ['', testSymbol],
request: ['', testSymbol]
},
dependencies: [ '' ],
dependencies: [''],
encapsulate: true
}))

const pluginCallbackWithOptions: FastifyPluginCallback<Options> = (fastify, options, next) => {
expectAssignable<string>(options.foo)
expectType<string>(options.foo)
}

expectAssignable<FastifyPluginCallback<Options>>(fastifyPlugin(pluginCallbackWithOptions))
expectType<FastifyPluginCallback<Options>>(fastifyPlugin(pluginCallbackWithOptions))

const pluginCallbackWithServer: FastifyPluginCallback<Options, Server> = (fastify, options, next) => {
expectAssignable<Server>(fastify.server)
expectType<Server>(fastify.server)
}

expectAssignable<FastifyPluginCallback<Options, Server>>(fastifyPlugin(pluginCallbackWithServer))
expectType<FastifyPluginCallback<Options, Server>>(fastifyPlugin(pluginCallbackWithServer))

const pluginCallbackWithTypeProvider: FastifyPluginCallback<Options, Server, TypeBoxTypeProvider> = (fastify, options, next) => {}
const pluginCallbackWithTypeProvider: FastifyPluginCallback<Options, Server, TypeBoxTypeProvider> = (fastify, options, next) => { }

expectAssignable<FastifyPluginCallback<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginCallbackWithTypeProvider))
expectType<FastifyPluginCallback<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginCallbackWithTypeProvider))

// Async

const pluginAsync: FastifyPluginAsync = async (fastify, options) => { }
expectAssignable<FastifyPluginAsync>(fastifyPlugin(pluginAsync))
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync))

const pluginAsyncWithTypes = async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }
expectAssignable<FastifyPluginAsync>(fastifyPlugin(pluginAsyncWithTypes))
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(pluginAsyncWithTypes))

expectAssignable<FastifyPluginAsync>(fastifyPlugin(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }))
expectAssignable<FastifyPluginAsync>(fastifyPlugin(pluginAsync, '' ))
expectAssignable<FastifyPluginAsync>(fastifyPlugin(pluginAsync, {
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }))
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, ''))
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, {
fastify: '',
name: '',
decorators: {
fastify: [ '', testSymbol ],
reply: [ '', testSymbol ],
request: [ '', testSymbol ]
fastify: ['', testSymbol],
reply: ['', testSymbol],
request: ['', testSymbol]
},
dependencies: [ '' ],
dependencies: [''],
encapsulate: true
}))

const pluginAsyncWithOptions: FastifyPluginAsync<Options> = async (fastify, options) => {
expectAssignable<string>(options.foo)
expectType<string>(options.foo)
}

expectAssignable<FastifyPluginAsync<Options>>(fastifyPlugin(pluginAsyncWithOptions))
expectType<FastifyPluginAsync<Options>>(fastifyPlugin(pluginAsyncWithOptions))

const pluginAsyncWithServer: FastifyPluginAsync<Options, Server> = async (fastify, options) => {
expectAssignable<Server>(fastify.server)
expectType<Server>(fastify.server)
}

expectAssignable<FastifyPluginAsync<Options, Server>>(fastifyPlugin(pluginAsyncWithServer))
expectType<FastifyPluginAsync<Options, Server>>(fastifyPlugin(pluginAsyncWithServer))

const pluginAsyncWithTypeProvider: FastifyPluginAsync<Options, Server, TypeBoxTypeProvider> = async (fastify, options) => {}
const pluginAsyncWithTypeProvider: FastifyPluginAsync<Options, Server, TypeBoxTypeProvider> = async (fastify, options) => { }

expectAssignable<FastifyPluginAsync<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginAsyncWithTypeProvider))
expectType<FastifyPluginAsync<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginAsyncWithTypeProvider))

// Fastify register

Expand All @@ -100,3 +104,63 @@ server.register(fastifyPlugin(pluginAsyncWithTypes))
server.register(fastifyPlugin(pluginAsyncWithOptions))
server.register(fastifyPlugin(pluginAsyncWithServer))
server.register(fastifyPlugin(pluginAsyncWithTypeProvider))

// properly handling callback and async
fastifyPlugin(function (fastify, options, next) {
expectType<FastifyInstance>(fastify)
expectType<Record<never, never>>(options)
expectType<(err?: Error) => void>(next)
})

fastifyPlugin<Options>(function (fastify, options, next) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
expectType<(err?: Error) => void>(next)
})

fastifyPlugin<Options>(async function (fastify, options) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
})

expectAssignable<FastifyPluginAsync<Options, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>>(fastifyPlugin(async function (fastify: FastifyInstance, options: Options) { }))
expectNotType<any>(fastifyPlugin(async function (fastify: FastifyInstance, options: Options) { }))

fastifyPlugin(async function (fastify, options: Options) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
})

fastifyPlugin(async function (fastify, options) {
expectType<FastifyInstance>(fastify)
expectType<Record<never, never>>(options)
})

expectError(
fastifyPlugin(async function (fastify, options: Options, next) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
})
)
expectAssignable<FastifyPluginCallback<Options>>(fastifyPlugin(function (fastify, options, next) { }))
expectNotType<any>(fastifyPlugin(function (fastify, options, next) { }))

fastifyPlugin(function (fastify, options: Options, next) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
expectType<(err?: Error) => void>(next)
})

expectError(
fastifyPlugin(function (fastify, options: Options, next) {
expectType<FastifyInstance>(fastify)
expectType<Options>(options)
return Promise.resolve()
})
)

server.register(fastifyExampleCallback, { foo: 'bar' })
expectError(server.register(fastifyExampleCallback, { foo: 'baz' }))

server.register(fastifyExampleAsync, { foo: 'bar' })
expectError(server.register(fastifyExampleAsync, { foo: 'baz' }))