Toggle navigation
集客麦麦@谢坤
首页
随笔
首页
>>
创作中心
>>
TS泛型与重载...
TS泛型与重载
[TOC] 在TypeScript中,泛型(Generics)和重载(Overloads)都是处理类型灵活性的重要特性,但它们的设计目的和使用场景有显著区别。下面详细解析两者的概念、区别及使用方式。 ### 一、泛型(Generics) #### 概念 泛型是一种**类型抽象机制**,允许在定义函数、接口、类时不预先指定具体类型,而是在**使用时动态指定类型**。其核心目的是**实现类型安全的代码复用**,让同一组件(函数/接口/类)能处理多种类型的数据,同时保持输入与输出类型的关联。 #### 基本使用 泛型通过`
`(T为类型变量,可自定义名称)来表示“待指定的类型”,使用时传入具体类型。 **示例1:泛型函数** 实现一个“输入什么类型,返回什么类型”的函数: ```typescript // 定义泛型函数,T为类型变量 function identity
(arg: T): T { return arg; } // 使用时指定类型(可省略,TS会自动推断) const num: number = identity
(100); // 正确,T=number const str: string = identity("hello"); // 正确,TS推断T=string ``` **示例2:泛型接口** 定义一个支持多种类型的数组接口: ```typescript interface Container
{ value: T; getValue: () => T; } // 使用时指定类型为string const strContainer: Container
= { value: "test", getValue: () => "test" }; ``` **示例3:泛型约束** 限制泛型只能是特定类型(通过`extends`): ```typescript // 约束T必须有length属性 interface HasLength { length: number; } function logLength
(arg: T): number { return arg.length; } logLength("hello"); // 正确(string有length) logLength([1, 2, 3]); // 正确(数组有length) logLength(100); // 错误(number无length) ``` ### 二、重载(Overloads) #### 概念 重载是指**为同一个函数定义多个不同的参数列表和返回类型**,以处理函数在不同调用场景下的类型差异。其核心目的是**让函数能根据不同参数(类型/数量)表现出不同的类型行为**。 #### 基本使用 重载需要先定义**多个“函数签名”**(声明参数和返回值类型),最后定义一个“实现签名”(包含具体逻辑,需兼容所有函数签名)。 **示例:处理不同参数的函数** 实现一个函数:接收字符串时返回字符串数组(拆分),接收数组时返回字符串(拼接): ```typescript // 1. 定义函数签名(重载声明) function convert(input: string): string[]; // 签名1:输入string,返回string[] function convert(input: string[]): string; // 签名2:输入string[],返回string // 2. 实现签名(需兼容所有签名) function convert(input: string | string[]): string | string[] { if (typeof input === "string") { return input.split(""); // 对应签名1 } else { return input.join(""); // 对应签名2 } } // 使用 const arr = convert("hello"); // 类型:string[](匹配签名1) const str = convert(["h", "i"]); // 类型:string(匹配签名2) ``` ### 三、泛型与重载的区别 | 维度 | 泛型(Generics) | 重载(Overloads) | |--------------|------------------------------------------|-------------------------------------------| | 核心目的 | 实现**类型安全的复用**,处理“同逻辑不同类型”的场景 | 处理**同一函数的不同调用形式**,解决“不同参数对应不同类型”的场景 | | 类型关联 | 强调输入与输出类型的**动态绑定**(如`T`贯穿始终) | 强调不同参数列表与返回值的**静态映射**(每个签名独立) | | 使用场景 | 通用组件(工具函数、集合类、高阶组件等) | 函数参数/返回值因场景不同而有显著差异(如多态行为) | | 代码复杂度 | 抽象程度高,减少重复代码 | 需定义多个签名,可能增加代码量(但逻辑更清晰) | **通俗理解**: - 泛型是“一套逻辑适配多种类型”(如“所有数组都能反转”); - 重载是“同一函数适配多种调用方式”(如“输入A做X,输入B做Y”)。 ### 四、使用场景对比 #### 适合用泛型的场景 - 实现通用工具函数(如数组操作、数据转换); - 定义可复用的组件(如React组件、类); - 需要保持输入输出类型一致的场景(如`Promise
`)。 **示例**:通用数组反转函数 ```typescript function reverseArray
(arr: T[]): T[] { return [...arr].reverse(); } const numArr = reverseArray([1, 2, 3]); // 类型:number[] const strArr = reverseArray(["a", "b"]); // 类型:string[] ``` #### 适合用重载的场景 - 函数参数类型/数量不同,导致处理逻辑或返回类型不同; - 需要明确区分函数的多种调用形式(提升类型提示清晰度)。 **示例**:处理不同类型的格式化函数 ```typescript // 签名1:格式化日期 function format(value: Date): string; // 签名2:格式化数字(保留n位小数) function format(value: number, decimal: number): string; // 实现 function format(value: Date | number, decimal?: number): string { if (value instanceof Date) { return value.toLocaleDateString(); } else { return value.toFixed(decimal || 0); } } format(new Date()); // 正确,返回日期字符串 format(123.456, 2); // 正确,返回"123.46" ```