介绍
在 TypeScript 中,函数返回值泛型的核心作用是:让函数的返回值类型,和入参类型/指定的类型保持一致,实现类型安全的复用,避免写重复代码。
理解
函数的返回值类型,由调用者自己决定,就叫返回值泛型
简单说:
普通函数:返回值类型写死,一辈子只能返回一种类型
返回值泛型函数:函数代码不改,想要什么类型,就返回什么类型
基础用法
自动推导返回值
泛型用 <T> 定义,TS 会自动根据入参推导返回值类型。
// 定义泛型函数:T 代表任意类型
function identity<T>(arg: T): T {
return arg; // 返回值类型 = 入参类型
}
// 使用
let str = identity("hello"); // str: string
let num = identity(123); // num: number
let bool = identity(true); // bool: boolean
✅ 优势:
- 不用为
string/number/boolean分别写函数 - 返回值类型完全精准,TS 会自动提示对应类型的属性/方法
手动指定返回值泛型
有时候 TS 无法自动推导,你可以手动传入泛型类型,强制规定返回值:
function getData<T>(): T {
// 模拟接口返回
return {} as T;
}
// 手动指定:返回值一定是 User 类型
interface User {
name: string;
age: number;
}
const user = getData<User>();
// user: User → TS 会自动提示 name、age
例子
一个全局 Map 存数据
存数据函数:没有泛型,普通参数
取数据函数:只有返回值是泛型
1、定义全局缓存仓库
// 全局缓存仓库,统一存页面全局数据
const globalCache = new Map<string, unknown>()
2、存数据函数
// 存数据:固定 key字符串,value任意值,不需要泛型
function setCache(key: string, value: unknown): void {
globalCache.set(key, value)
console.log("保存成功:", key)
}
3. 无泛型 纯普通获取(原始写法,不推荐)
// 无泛型,返回固定 unknown
function getCache(key: string): unknown {
return globalCache.get(key)
}
使用
// 拿到的变量全是 unknown 类型
const user = getCache("userInfo")
const token = getCache("token")
// ❌ 直接使用全部报错
// user.name // 报错:类型“unknown”上不存在属性“name”
// token.length // 报错:类型“unknown”上不存在属性“length”
强行使用只能手动类型断言
// 每次取值都要手动写断言,重复、繁琐
const user = getCache("userInfo") as { name: string; age: number }
const token = getCache("token") as string
user.name
token.length
无泛型缺点
- 默认返回
unknown,无任何代码提示 - 访问属性/方法直接红线报错
- 每一次取值都要手动
as 类型,代码冗余 - 类型写错不会及时校验,容易埋线上bug
4. 返回值泛型(推荐)
// 入参 key 固定 string,无泛型
// 只有返回值 T 为泛型,由调用方传入类型
function getCache<T>(key: string): T {
return globalCache.get(key) as T
}
使用
// 取值时 显式传入泛型类型,直接锁定返回值类型
const user = getCache<{ name: string; age: number }>("userInfo")
const token = getCache<string>("token")
// ✅ 完美智能提示
user.name
user.age
token.length
token.trim()
也可以抽离接口,更优雅(企业常用)
interface UserInfo {
name: string
age: number
}
// 语义更清晰,复用类型
const user = getCache<UserInfo>("userInfo")
5、企业真实使用场景
// 1、先存数据(普通存储,不用管类型)
setCache("userInfo", { name: "李四", age: 20 })
setCache("token", "abc123456")
// 2、取数据【返回值泛型生效】
// 取用户,自动识别用户对象类型
const user = getCache<{ name: string; age: number }>("userInfo")
user.name // ✅ 有提示,乱写报错
// 取令牌,自动识别字符串类型
const token = getCache<string>("token")
token.length // ✅ 字符串方法提示
两种写法核心对比
| 对比项 | 无泛型(unknown) | 返回值泛型<T> |
|---|---|---|
| 返回类型 | 固定 unknown | 调用方自定义 T |
| 代码提示 | 无 | 完整属性/方法提示 |
| 类型安全 | 差,全靠手动断言 | 强类型约束 |
| 重复代码 | 每次取值必写 as xxx |
一次指定类型,直接用 |
| 错误校验 | 类型错误不易发现 | 写错类型直接TS红线 |
返回值泛型 核心好处
存的时候随便存
setCache保持简单,unknown兼容所有数据,不用复杂泛型。取的时候精准约束
只有读取时才声明类型,读写分离,符合缓存业务逻辑。杜绝隐式类型错误
// 泛型约束下,写错类型直接报错 const token = getCache<number>("token") // 明知是字符串,写成 number,编码阶段就预警多人协作友好
别人看代码一眼就知道:这个key对应什么数据结构。
一句话总结
返回值泛型的作用:函数逻辑写死不变,参数正常干活不变,只有返回值类型,随业务自己定义。
不写死类型、不用 any、类型不丢失、一个函数通用所有场景。