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

TypeScript中如何复用多函数重载?重复重载代码优化求助

复用TypeScript函数重载定义的解决方案

你遇到的这个重复重载维护问题确实很头疼——每次修改都要同步两个地方,很容易出错。好在TypeScript有几种方式可以帮你复用这些重载逻辑,不用重复写一堆相同的泛型签名。


方法1:提取重载到类型别名,在类中复用

首先,我们可以把所有slice的重载签名提取成一个函数类型别名,这样两个类都能直接引用这个类型,不用重复定义:

// 先定义通用的slice重载类型,S是原对象的类型
type SliceOverloads<S> = {
  <Key extends keyof S>(key: Key): Slice<S[Key], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1]>(key1: Key1, key2: Key2): Slice<S[Key1][Key2], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2]>(key1: Key1, key2: Key2, key3: Key3): Slice<S[Key1][Key2][Key3], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2], Key4 extends keyof S[Key1][Key2][Key3]>(key1: Key1, key2: Key2, key3: Key3, key4: Key4): Slice<S[Key1][Key2][Key3][Key4], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2], Key4 extends keyof S[Key1][Key2][Key3], Key5 extends keyof S[Key1][Key2][Key3][Key4]>(key1: Key1, key2: Key2, key3: Key3, key4: Key4, key5: Key5): Slice<S[Key1][Key2][Key3][Key4][Key5], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2], Key4 extends keyof S[Key1][Key2][Key3], Key5 extends keyof S[Key1][Key2][Key3][Key4], Key6 extends keyof S[Key1][Key2][Key3][Key4][Key5]>(key1: Key1, key2: Key2, key3: Key3, key4: Key4, key5: Key5, key6: Key6): Slice<S[Key1][Key2][Key3][Key4][Key5][Key6], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2], Key4 extends keyof S[Key1][Key2][Key3], Key5 extends keyof S[Key1][Key2][Key3][Key4], Key6 extends keyof S[Key1][Key2][Key3][Key4][Key5], Key7 extends keyof S[Key1][Key2][Key3][Key4][Key5][Key6]>(key1: Key1, key2: Key2, key3: Key3, key4: Key4, key5: Key5, key6: Key6, key7: Key7): Slice<S[Key1][Key2][Key3][Key4][Key5][Key6][Key7], S>;
  <Key1 extends keyof S, Key2 extends keyof S[Key1], Key3 extends keyof S[Key1][Key2], Key4 extends keyof S[Key1][Key2][Key3], Key5 extends keyof S[Key1][Key2][Key3][Key4], Key6 extends keyof S[Key1][Key2][Key3][Key4][Key5], Key7 extends keyof S[Key1][Key2][Key3][Key4][Key5][Key6], Key8 extends keyof S[Key1][Key2][Key3][Key4][Key5][Key6][Key7]>(key1: Key1, key2: Key2, key3: Key3, key4: Key4, key5: Key5, key6: Key6, key7: Key7, key8: Key8): Slice<S[Key1][Key2][Key3][Key4][Key5][Key6][Key7][Key8], S>;
  (...keys: string[]): any;
};

然后在你的Atom类(以及另一个需要的类)里,直接用这个类型来定义slice方法,只需要实现一次方法体:

export class Atom<S> {
  constructor(private initial: S) { }

  // 直接引用预定义的重载类型
  slice: SliceOverloads<S> = (...keys: string[]) => {
    return new Slice(this, keys);
  };
}

这样一来,所有的重载逻辑都集中在SliceOverloads里,后续修改只需要改这一个地方,所有引用它的类都会自动更新类型。


方法2:用接口实现重载复用

另一种方式是定义一个包含slice重载的接口,让需要的类实现这个接口。这种方式更符合面向对象的设计思路:

// 定义接口,包含所有slice重载
interface HasSlice<S> {
  slice<Key extends keyof S>(key: Key): Slice<S[Key], S>;
  slice<Key1 extends keyof S, Key2 extends keyof S[Key1]>(key1: Key1, key2: Key2): Slice<S[Key1][Key2], S>;
  // ... 其余重载和上面一致
  slice(...keys: string[]): any;
}

// 让Atom类实现这个接口
export class Atom<S> implements HasSlice<S> {
  constructor(private initial: S) { }

  // 只需要实现一次方法体,重载签名由接口自动提供
  slice(...keys: string[]) {
    return new Slice(this, keys);
  }
}

这种方式的好处是,你可以强制所有需要slice方法的类遵循相同的重载规则,而且修改接口就能同步所有实现类的类型。


为什么你之前的尝试丢失了类型推导?

你之前把slice抽成独立函数,但类里的方法没有保留重载签名——TypeScript只会识别最后那个实现签名的类型,所以丢失了之前的泛型推导能力。上面两种方法都是把重载签名集中定义,让类直接复用这些签名,从而保留完整的类型推导。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 19:28:13