← 返回题目列表

TypeScript 函数重载怎么写?适合什么场景?

高频 中等 第 11 / 32 题 更新于 2026/07/29
TypeScript函数重载类型设计

简化版

TypeScript 函数重载是为同一个函数声明多组调用签名,再用一个实现签名承接具体逻辑。它适合“入参形态不同,返回类型也跟着变化”的 API,但实现签名必须兼容所有重载签名。

详细版

示例:

function format(value: string): string;
function format(value: number): string;
function format(value: string | number) {
  return String(value);
}

前两行是重载签名,最后一行是实现签名。 调用方只能看到重载签名,看不到实现签名。 面试重点是:重载顺序、实现兼容、和联合类型的取舍。

完整版教学

一、重载解决返回类型随入参变化的问题

联合类型可以表达多个入参类型。 但如果返回类型和具体入参强相关,单纯联合类型可能不够精确。 函数重载可以给不同调用方式配置不同返回类型。

function get(id: number): User;
function get(ids: number[]): User[];
function get(input: number | number[]) {
  return Array.isArray(input) ? input.map(id => ({ id })) : { id: input };
}

1 返回 User。 传 [1, 2] 返回 User[]。 这比直接写 (number | number[]) => User | User[] 更方便调用方使用。

二、重载签名和实现签名要分清

重载函数由多条重载签名和一条实现签名组成。 重载签名给调用方看。 实现签名负责真实函数体,并且必须能覆盖所有重载情况。

function parse(value: string): object;
function parse(value: Buffer): object;
function parse(value: string | Buffer): object {
  return JSON.parse(value.toString());
}

流程如下:

调用方传参
  -> TS 从上到下匹配重载签名
  -> 选中某个调用签名
  -> 运行时执行同一个函数体

实现签名不是额外的公开重载。 如果调用方式只符合实现签名但不符合任何重载签名,调用方仍会报错。

三、重载顺序会影响匹配

TypeScript 会按顺序匹配重载签名。 更具体的签名应该放在更前面,更宽泛的签名放后面。 否则宽泛签名可能提前吃掉调用,导致返回类型不够准确。

function fn(value: 'a'): 1;
function fn(value: string): number;
function fn(value: string) {
  return value === 'a' ? 1 : 0;
}

const x = fn('a'); // 1

如果把 string 签名放在前面,'a' 可能先匹配宽泛签名。 面试里提到重载顺序,说明你知道它不是简单声明堆叠。

四、联合类型和重载怎么选

如果返回类型不随入参变化,联合类型通常更简单。 如果不同入参对应明显不同返回类型,重载更清晰。 不要为了展示技巧而滥用重载。

场景推荐
入参多种类型,返回固定联合类型
入参和返回一一对应函数重载
API 分支很多且复杂考虑拆函数或泛型
回调类型高度相关重载或泛型

例如 format(string | number): string 用联合类型即可。 query(id): Itemquery(ids): Item[] 更适合重载。

五、重载不改变运行时实现

TypeScript 重载只是类型层面的多个调用签名。 编译后 JavaScript 里只有一个函数实现。 所以运行时仍要自己判断参数类型。

function double(value: string): string;
function double(value: number): number;
function double(value: string | number) {
  if (typeof value === 'string') return value + value;
  return value * 2;
}

记忆钩子:重载给类型系统多张入口说明书,运行时还是同一个门。

如果实现里没有正确分支处理,类型再漂亮也挡不住运行时错误。

六、箭头函数重载要换写法

函数声明天然支持多条重载签名。 箭头函数不能直接写多条同名声明。 可以用接口或类型别名声明多个调用签名,再赋值实现。

type Double = {
  (value: string): string;
  (value: number): number;
};

const double: Double = (value: string | number) => {
  return typeof value === 'string' ? value + value : value * 2;
};

这在 React hooks、工具函数导出中经常遇到。 如果团队偏爱箭头函数,要知道这种替代写法。

七、常见误区与追问

  • 误区:实现签名也能被调用方直接使用。 调用方只按重载签名检查,实现签名不作为公开调用入口。
  • 误区:重载会生成多个 JavaScript 函数。 编译后只有一个实现函数,重载只存在于类型层。
  • 误区:所有联合类型都应该改成重载。 返回类型不随入参变化时,联合类型通常更简单。
  • 追问:重载签名顺序怎么放? 更具体的放前面,更宽泛的放后面。
  • 追问:实现签名要满足什么条件? 它必须能兼容所有重载签名的参数和返回处理。
  • 追问:箭头函数怎么实现重载? 用带多个调用签名的 type 或 interface 描述函数类型,再赋值实现。

八、加强记忆

函数重载按“三段”记:多条公开重载签名,一条宽泛实现签名,一个运行时分支实现。选择时看返回类型是否随入参改变;如果只是参数可以多种类型,联合类型往往更清楚。