Declaring multiple typescript PluginProperties yields errors at runtime
mattgif opened this issue · comments
Support plan
- is this issue currently blocking your project? (yes/no): No
- is this issue affecting a production system? (yes/no): No
Context
- node version: 16.19.1
- module version: 21.3.2
- environment (e.g. node, browser, native): node
- used with (e.g. hapi application, another framework, standalone, ...): Hapi, Boom
- any other relevant information:
How can we help?
What is the recommended approach for declaring the typescript interface for PluginProperties in Hapi 21?
Formerly (upgrading from Hapi 17), we could do this by declaring a module. But doing this in v21 with multiple plugins yields the following error at runtime: error TS2339: Property 'X' does not exist on type 'PluginProperties'.
(where 'X' is the name of some declared plugin).
In the code example below handler.ts is the module that throws the error:
myPlugin.ts
declare module '@hapi/hapi' {
interface PluginProperties {
MyPlugin: {
foo: Record<string,string>
}
}
}
export default {
name: 'MyPlugin',
version: '1.0.0',
async register(server: Server): Promise<void> {
server.expose('foo', {
bar: 'Hello world'
})
}
}
anotherPlg.ts
import { Server } from '@hapi/hapi'
declare module '@hapi/hapi' {
interface PluginProperties {
Other: {
bar: Record<string,string>
}
}
}
export default {
name: 'Other',
version: '1.0.0',
async register(server: Server): Promise<void> {
server.expose('bar', {
baz: 'Hello, other world'
})
}
}
handler.ts
import { Request, ResponseToolkit } from '@hapi/hapi'
export default function handler (request: Request, h: ResponseToolkit) {
const {
server: {
plugins: {
MyPlugin: {
foo
},
Other: {
bar
}
}
}
} = request
console.log( foo.bar, bar.baz )
return h.response().code(200);
}
index.ts
import * as Hapi from "@hapi/hapi";
import MyPlugin from "./myPlugin";
import AnotherPlg from "./anotherPlg";
import handler from "./handler";
const init = async () => {
const server = Hapi.server({
port: 3000,
host: "localhost",
});
await server.register(MyPlugin);
await server.register(AnotherPlg);
server.route({
method: "GET",
path: "/",
handler,
});
await server.start();
};
init();
Which version of typescript are you using? I had the same thing for versions < 4.9.
Which version of typescript are you using? I had the same thing for versions < 4.9.
v4.9.5
My workaround for now is an interface declaration like so:
export interface RequestWithPlugins<DataParams = Record<string,any>,QueryParams extends RequestQuery = Record<string,any>> extends Request {
server: Server<ServerApplicationState> & {
plugins: MyPlg & MyOtherPlg & YetAnotherPlg;
query?: QueryParams;
data?: DataParams;
};
}
Where my plugin interfaces look something like:
interface MyPlg extends PluginProperties {
MyPlugin: {
foo: {
bar: 'Hello, world';
};
};
}