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

TypeScript合并多工具类/函数对象时如何保留类型与实例配置?

TypeScript 合并多个工具类实例并保留类型提示与私有配置

核心问题分析

你需要合并多个工具类实例,同时保留所有方法的类型智能提示,但遇到两个关键问题:

  1. 原始合并函数的泛型推断错误,返回类型为Record<never, TUtilityFunction>;
  2. 类中同名私有属性config导致直接扩展实例时类型丢失,且需要保留各实例的配置上下文。

解决方案

通过自定义类型工具过滤方法属性、合并类型,并在实现中避免私有属性冲突,同时保留方法的原实例上下文。

1. 定义类型工具

首先创建几个类型工具来处理类型提取与合并:

// 提取对象中所有可枚举的方法属性(自动排除私有/受保护属性)
type PickPublicMethods<T> = {
  [K in keyof T as T[K] extends Function ? K : never]: T[K]
};

// 辅助类型:将联合类型转换为交叉类型,用于合并多个对象的方法类型
type UnionToIntersection<U> = 
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

// 合并多个工具实例的方法类型为最终对象类型
type MergeUtilities<T extends Record<string, object>> = {
  [K in keyof UnionToIntersection<PickPublicMethods<T[keyof T]>>]: 
    UnionToIntersection<PickPublicMethods<T[keyof T]>>[K]
};

2. 实现合并函数

实现一个函数,只提取每个实例的方法属性进行合并,避开私有属性:

export const combineUtilities = <T extends Record<string, object>>(utilities: T): MergeUtilities<T> => {
  return Object.values(utilities).reduce((merged, utility) => {
    // 过滤出当前实例中的所有方法属性
    const methods = Object.fromEntries(
      Object.entries(utility).filter(([_, value]) => typeof value === 'function')
    );
    return { ...merged, ...methods };
  }, {} as MergeUtilities<T>);
};

3. 测试与验证

用你的实际类结构测试,确保类型提示和私有配置正常工作:

// 示例类型定义
type TSomeConfigType = { apiUrl: string };
type SomeCustomType = { id: number; name: string };

class UtilityA {
  private readonly config: TSomeConfigType;

  constructor(config: TSomeConfigType) {
    this.config = config;
  }

  DoSomeWork = (arg1: SomeCustomType, arg2: string): SomeCustomType => {
    console.log(this.config.apiUrl); // 仍能访问原实例的私有配置
    return arg1;
  };
}

class UtilityB {
  private readonly config: TSomeConfigType;

  constructor(config: TSomeConfigType) {
    this.config = config;
  }

  DoSomeOtherWork = (arg1: SomeCustomType, arg2: number): SomeCustomType => {
    console.log(this.config.apiUrl); // 仍能访问原实例的私有配置
    return arg1;
  };
}

// 使用合并函数
const utilA = new UtilityA({ apiUrl: 'https://a.example.com' });
const utilB = new UtilityB({ apiUrl: 'https://b.example.com' });

const merged = combineUtilities({ utilA, utilB });
// 此时merged会有完整的智能提示:
// merged.DoSomeWork(arg1: SomeCustomType, arg2: string): SomeCustomType
// merged.DoSomeOtherWork(arg1: SomeCustomType, arg2: number): SomeCustomType
merged.DoSomeWork({ id: 1, name: 'test' }, 'foo');
merged.DoSomeOtherWork({ id: 2, name: 'test2' }, 123);

关键原理说明

  • 类型过滤:PickPublicMethods自动排除私有/受保护属性,因为这类属性在外部类型层面不可访问,不会出现在keyof T中。
  • 类型合并:UnionToIntersection将多个工具类的方法类型联合转为交叉类型,确保合并后的对象包含所有方法的准确类型。
  • 上下文保留:类中的方法用箭头函数定义时,已经绑定了原实例的this,因此合并到新对象后,方法仍能访问原实例的私有config,无需在合并对象中保留该属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:48:19