Reputation: 1845
I am writing a library using ts, and get some trouble when trying to extend core module type. Here is the project structure.
- src
- core
- core.ts
- plugins
- insert
- index.ts
code in core.ts
export interface Commands {}
export class Core {
commands: Commands;
constructor() {
this.commands = {};
}
registerCommands(name: string, func: any) {
// @ts-ignore
this.commands[name] = func;
}
}
code in insert/index.ts
import { Core } from "../../core/core";
export class InsertPlugin {
constructor(core: Core) {
core.registerCommands("insert", this.insert.bind(this));
}
insert(value: string) {
console.log("insert " + value);
}
}
InsertPlugin
using core.registerCommands
to register a command insert
to core.
My question is how can some one using my library get types for insert
command. For example
// assume the name of the library is core
import { createCore } from 'core'
const core = createCore()
// How can i get types for insert method
core.commands.insert()
I have create a complete demo for above code, https://github.com/clinyong/ts-extends-core-commands.
Also I have read the typescript handbook for plugin types, https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-plugin-d-ts.html.
Upvotes: 0
Views: 227
Reputation: 636
What's interesting with your example is that accessing core.commands.insert()
is only valid after you create a new InsertPlugin(core)
instance (which you don't do in your example).
Given this, you can actually encode this requirement if you were to use a function with an assertion return type, rather than a class.
insert/index.ts
:
import { Core } from "../../core/core";
function registerInsertPlugin(core: Core): asserts core is (Core & {
commands: {
insert: typeof insert
}
}) {
const insert = (value: string) => {
console.log("insert " + value);
}
core.registerCommands("insert", insert);
}
Then you can use it like this:
import { createCore } from 'core'
import { registerInsertPlugin } from 'insert'
const core = createCore();
registerInsertPlugin(core);
core.commands.insert('hello world');
Forgetting to call registerInsertPlugin
will result in a valid type error:
import { createCore } from 'core'
const core = createCore();
core.commands.insert('hello world');
// ^ Property 'insert' does not exist on type 'Commands'
Beyond this, you will then be able to also create multiple "plugins", each of which will expand core.commands
with the relevant types:
const core = createCore();
registerInsertPlugin(core);
registerUpsertPlugin(core);
core.commands.insert('hello world');
core.commands.upsert("hello world");
/* Resulting Type:
* const core: Core & {
* commands: {
* insert: (value: string) => void;
* };
* } & {
* commands: {
* upsert: (value: string) => void;
* };
* }
*/
Upvotes: 1