I am using a package — ko-component-router — with the following (condensed) type definitions...
index.d.ts
export { IContext, Context } from './context';
export { Router } from './router';
context.d.ts
export interface IContext {
$root: IContext;
$child: IContext;
$children: IContext[];
$parent: IContext;
$parents: IContext[];
router: Router;
route: Route;
params: {
[k: string]: any;
};
path: string;
pathname: string;
base: string;
canonicalPath: string;
}
export declare class Context implements IContext {
// ...
}
router.d.ts
import { IContext } from './context';
export declare type Middleware = (ctx: IContext, done?: () => any) => {
beforeRender?: (done?: () => void) => Promise<any> | void;
afterRender?: (done?: () => void) => Promise<any> | void;
beforeDispose?: (done?: () => void) => Promise<any> | void;
afterDispose?: (done?: () => void) => Promise<any> | void;
};
export declare class Router {
static use(...fns: Middleware[]): void;
}
On the consumer side, middleware is registered that can add properties to the context that is passed into the view component, as such...
import { Router } from 'ko-component-router'
Router.use((ctx) => ({
beforeRender() {
ctx.someProperty = 'foo'
}
}))
As expected, a Property 'someProperty' does not exist on type 'IContext'
error is thrown by the compiler.
Based on the documentation on declaration merging, I attempted adding the following in order to make the compiler aware of this new property...
import { Router } from 'ko-component-router'
declare module 'ko-component-router' {
interface IContext {
someProperty: string
}
}
Router.use((ctx) => ({
beforeRender() {
ctx.someProperty = 'foo'
}
}))
But the same error is thrown. I've tried just about everything I can think of, but I'm unable to make the compiler aware of this new property without completely re-implementing the type definitions in my project, which is obviously far from ideal.
Is this possible, and if so, where am I going astray?
As mentioned in cartant's comment, module augmentation does not work for classes and interfaces that are exported "indirectly" - this is a known issue.
It works if you augment the inner module where IContext
is defined:
declare module 'ko-component-router/context' {
export interface IContext {
someProperty: string
}
}
Unfortunately, anyone who adds augmentations in this way introduces a dependency on internal structure of your library.
Also, with this augmentation class Context
does not compile anymore:
error TS2420: Class 'Context' incorrectly implements interface 'IContext'. Property 'someProperty' is missing in type 'Context'.
So if you add properties to interfaces which are implemented by some classes, these properties must be optional:
declare module 'ko-component-router/context' {
export interface IContext {
someProperty?: string
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With