You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TS单包中实现导入触发的条件模块扩展插件系统?

基于TypeScript实现单包插件系统的解决方案

尝试复刻Dayjs式条件模块扩展(有局限)

Dayjs的插件依赖TS的模块声明合并+静态解析特性,但纯TS项目中要实现「仅导入插件才生效类型扩展」,需要结合条件类型+运行时符号标记来规避未导入时的类型生效问题:

  • 每个插件文件导出一个唯一的符号(如export const __PLUGIN_ENABLED__ = Symbol()),用于标记插件已被导入。
  • 在插件的类型声明文件中,通过条件类型判断该符号是否存在,仅当存在时才扩展主库的类型:
    // plugin/aggregate.d.ts
    import type { MongoLibInstance } from '../main'
    import { __PLUGIN_ENABLED__ } from './aggregate'
    
    declare module '../main' {
      // 仅当插件被导入,__PLUGIN_ENABLED__存在时,才应用类型扩展
      interface MongoLibInstance extends (typeof __PLUGIN_ENABLED__ extends never ? {} : {
        advancedAggregate: (pipeline: any[]) => Promise<any>
      }) {}
    }
    
  • 主库的extend方法中,仅当插件被显式调用后才挂载对应方法,同时用类型守卫确保运行时的安全性。

注意:这种方式有明显局限——TS静态解析特性可能导致类型判断不够精准,若用户未导入插件但手动引用插件类型,仍会出现类型错误,且每个插件都需单独维护条件类型逻辑。

TS友好的替代插件模式(无需多包发布)

如果复刻Dayjs模式的成本过高,以下几种模式更适配TS的静态类型系统:

1. 显式类型注入模式

主库提供基础类型和扩展方法,插件导出自身的扩展类型与实现,用户手动合并类型,完全规避自动类型扩展的问题:

  • 主库实现:
    // main.ts
    export interface BaseMongoLib {}
    export class MongoLib implements BaseMongoLib {
      extend<T>(plugin: (instance: this) => T): this & T {
        Object.assign(this, plugin(this))
        return this as this & T
      }
    }
    
  • 插件实现:
    // plugin/aggregate.ts
    export interface AggregatePlugin {
      advancedAggregate: (pipeline: any[]) => Promise<any>
    }
    export function aggregatePlugin(instance: BaseMongoLib): AggregatePlugin {
      return {
        advancedAggregate: async (pipeline) => {
          // 具体实现逻辑
        }
      }
    }
    // 提供辅助类型简化用户合并操作
    export type WithAggregate<T> = T & AggregatePlugin
    
  • 用户使用:
    import { MongoLib } from 'my-mongo-lib'
    import { aggregatePlugin, WithAggregate } from 'my-mongo-lib/plugin/aggregate'
    
    const db = new MongoLib().extend(aggregatePlugin) as WithAggregate<MongoLib>
    // 此时db.advancedAggregate拥有完整类型提示
    
    优点:类型完全可控,未导入插件时不会自动扩展类型,主库原定义无报错;实现简单,无需复杂的模块声明。
    缺点:用户需手动合并类型,但可通过辅助类型简化操作。

2. 插件注册式类型扩展

主库定义全局类型注册表,插件向注册表注入自身类型,用户必须显式导入插件并调用extend启用:

  • 主库实现:
    // main.ts
    declare global {
      // 全局插件类型注册表,默认为空
      interface MongoLibPlugins {}
    }
    
    export interface BaseMongoLib {}
    export class MongoLib implements BaseMongoLib {
      extend<K extends keyof MongoLibPlugins>(pluginKey: K): this & MongoLibPlugins[K] {
        // 动态加载插件(需确保TS配置支持动态导入)
        const plugin = require(`./plugin/${pluginKey}`).default
        Object.assign(this, plugin(this))
        return this as this & MongoLibPlugins[K]
      }
    }
    
  • 插件实现:
    // plugin/aggregate.ts
    declare global {
      interface MongoLibPlugins {
        aggregate: {
          advancedAggregate: (pipeline: any[]) => Promise<any>
        }
      }
    }
    
    export default function aggregatePlugin(instance: BaseMongoLib) {
      return {
        advancedAggregate: async (pipeline) => {
          // 具体实现逻辑
        }
      }
    }
    
  • 用户使用:
    import { MongoLib } from 'my-mongo-lib'
    // 必须导入插件,否则注册表中无aggregate类型
    import 'my-mongo-lib/plugin/aggregate'
    
    const db = new MongoLib().extend('aggregate')
    // db.advancedAggregate自动获得类型提示
    
    优点:用户只需导入插件并调用extend,类型自动合并;未导入插件时,extend不会提示对应的插件key,避免误用。
    缺点:依赖全局接口扩展,严格模式下可能需配置skipLibCheck确保类型兼容。

3. 装饰器模式(类扩展场景)

通过类装饰器实现插件扩展,用户用装饰器包裹主类即可启用插件,完全符合TS的类扩展特性:

  • 主库实现:
    // main.ts
    export class MongoLib {
      // 基础方法实现
    }
    
  • 插件实现:
    // plugin/aggregate.ts
    export function withAggregate<T extends typeof MongoLib>(Base: T) {
      return class extends Base {
        advancedAggregate(pipeline: any[]): Promise<any> {
          // 具体实现逻辑
        }
      }
    }
    
  • 用户使用:
    import { MongoLib } from 'my-mongo-lib'
    import { withAggregate } from 'my-mongo-lib/plugin/aggregate'
    
    const EnhancedMongoLib = withAggregate(MongoLib)
    const db = new EnhancedMongoLib()
    // db.advancedAggregate拥有完整类型提示
    
    优点:类型安全,插件逻辑封装性好,用户使用直观;支持多插件叠加(嵌套装饰器)。
    缺点:仅适用于类扩展场景,无法直接扩展静态成员(需额外处理)。

内容的提问来源于stack exchange,提问作者strblr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 03:25:00