首页 > 解决方案 > 如何在打字稿中扩展其他模块的类型

问题描述

我正在使用 ts 编写一个库,在尝试扩展核心模块类型时遇到了一些麻烦。这是项目结构。

- src
  - core
    - core.ts
  - plugins
    - insert
      - index.ts

代码在core.ts

export interface Commands {}

export class Core {
  commands: Commands;

  constructor() {
    this.commands = {};
  }

  registerCommands(name: string, func: any) {
    // @ts-ignore
    this.commands[name] = func;
  }
}

代码在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用于向核心core.registerCommands注册命令insert

我的问题是使用我的库的人如何获取insert命令类型。例如

// 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()

我为上述代码创建了一个完整的演示,https://github.com/clinyong/ts-extends-core-commands

我还阅读了插件类型的打字稿手册,https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-plugin-d-ts.html

标签: typescript

解决方案


您的示例有趣的是,访问core.commands.insert()您创建new InsertPlugin(core)实例后才有效(您在示例中没有这样做)。

鉴于此,如果您要使用具有断言返回类型的函数而不是类,则实际上可以对这个要求进行编码。

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);
}

然后你可以像这样使用它:

import { createCore } from 'core'
import { registerInsertPlugin } from 'insert'

const core = createCore();
registerInsertPlugin(core);
core.commands.insert('hello world');

忘记调用registerInsertPlugin将导致有效类型错误:


import { createCore } from 'core'

const core = createCore();
core.commands.insert('hello world');
// ^ Property 'insert' does not exist on type 'Commands'

除此之外,您还可以创建多个“插件”,每个插件都将扩展core.commands相关类型:

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;
 *     };
 * }
 */

推荐阅读