首页 > 解决方案 > 如何合并打字稿模块定义

问题描述

我有一个包含自定义.d.ts文件的 JavaScript 模块。让我们调用模块Foobar

foob​​ar.js

function foobar (opts) {
  this.register = plugin => {
    plugin(this)
  }

  this.decorate = (prop, value) => {
    this[prop] = value
  }

  return this
}
export default foobar

foob​​ar.d.ts

export interface FoobarPlugin {
  (inst: FoobarInst): void
}

export interface FoobarInst {
  register(plugin: FoobarPlugin): void
  decorate(prop: string, value: any): void
}

export default function foobar (): FoobarInst

我也有插件:

fuzzbuzz.js

function fuzzbuzz (inst) {
  inst.decorate('fuzzbuzz', true)
}

export default fuzzbuzz

fuzzbuzz.d.ts

import { FoobarInst } from '../foobar/foobar'

export default function fuzzbuzz (inst: FoobarInst): void

我将插件加载到我的模块中:

索引.ts

import foobar from './foobar/foobar'
import fuzzbuzz from './fuzzbuzz/fuzzbuzz'

const inst = foobar()

inst.register(fuzzbuzz)

inst.fuzzbuzz // -> true

为了更新 FoobarInst 类型定义,我需要向 fuzzbuzz.d.ts 添加什么?

我尝试了以下变化:

declare module foobar {
  interface FoobarInst {
    fuzzbuzz: boolean
  }
}

我的tsconfig.json样子:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true
    "forceConsistentCasingInFileNames": true, 
    "resolveJsonModule": true,
  }
}

感谢您提供任何帮助!

标签: javascripttypescript

解决方案


您正在寻找的是模块扩充。我认为,import缺少fuzzbuzz.d.ts让 TS 识别的声明,即给定的声明扩展/增加了一个已经存在的"foobar"模块:

fuzzbuzz.d.ts:

import { FoobarOpts } from "foobar"; // can be any import, preferrably one of "foobar" 

declare module "foobar" {
  // your module extensions
}

关于插件架构

插件扩展必须由编译器静态分析。这意味着,您不能在调用或通过动态导入时使 TSfoobar 增强 foobar.register(fuzzbuzz)

fuzzbuzz.d.ts相反,当通过模块解析或在项目目录中自动包含 / 文件作为编译.ts输入包含时,该模块被视为增强型。.d.ts因此,将类型扩充放在一个模块中是有意义的foobar.register(fuzzbuzz),以便类型和运行时代码同步。一个最小的例子:

foob​​ar.ts:

declare module "foobar" {
  // Plugin gets the options and possibly some internal "foobar" state
  type Plugin = (opts: FoobarOpts, state: {}) => void;

  interface FoobarOpts {
    foo: string;
    bar: number;
  }

  export default function foobar(opts: FoobarOpts): void;

  function register(plugin: Plugin): void;
}

我的插件.ts:

import { register, Plugin, FoobarOpts } from "foobar";

const fuzzBuzzPlugin: Plugin = (opt: FoobarOpts, state) => {
  opt.fuzzbuzz; // fuzzbuzz available now.
};

// set type augmentation...
declare module "foobar" {
  export interface FoobarOpts {
    fuzzbuzz: boolean;
  }
}

// ... and run-time plugin extension in one module, so they go hand in hand
register(fuzzBuzzPlugin);

客户端.ts:

import foobar from "foobar";

foobar({ bar: 42, foo: "buh", fuzzbuzz: true }); // works with fuzzbuzz

推荐阅读