1.T 是 泛型的“类型变量”(type parameter)。
T是什么:
- T 不是值、不是变量、也不是关键字
- 它代表“某一种类型”,具体是哪种类型,由你调用函数时传入的值来推出来(或你手动写出来)。
深深理解:
function wrap<T>(value: T): T
<T>:声明一个泛型类型变量 T
(value: T):这是接收参数,参数名叫 value,参数类型是 T
: T(括号后面那个):这是返回值类型,表示函数返回一个 T
所以:
- 接收参数:value: T
- 返回类型:最后的 : T
2.可以随便取名字:
类型变量(泛型参数)名字可以随便取,只要是合法标识符即可。
常见命名习惯(推荐)
-
通用:
T、U、V -
更语义化(更好读):
TData、TItem、TResponse、TKey
例子:
function wrap<TData>(value: TData): TData {
return value
}
注意 1 点
在同一个 <...> 作用域里,名字要一致才表示同一个类型:
<T>(a: T, b: T)表示 a 和 b 同类型
<T, U>(a: T, b: U)表示可以不同类型
例子:
function wrap<T>(value: T): T {
return value
}
这里的意思是:
- T 表示“value 的类型”
- 你传什么类型进来,T 就是什么类型
- 返回值类型也跟着是 T
调用时:
const a = wrap(123) // 123 是 number,所以 T = number,a: number
const b = wrap('hi') // 'hi' 是 string,所以 T = string,b: string
为什么要用 T
因为你想写一个通用函数:同一段代码既能处理 number,也能处理 string,还能保持“类型不丢失”。
T 这个字母可以换吗
可以,随便叫:
- T(最常见:Type)
- U、K、V
- TItem、TData、TResponse(更语义化)
比如:
function wrap<TData>(value: TData): TData {
return value
}
T 在“好几处地方”出现时,你可以用一个统一理解方式:
- 同一个函数/类型定义里,T 是同一个“类型占位符”。它在不同位置出现,是在表达“这些位置的类型彼此有关联”。
- 调用时确定一次 T 是什么类型,整个签名里所有 T 都一起跟着确定。
(1)最典型:参数是 T,返回也是 T
function wrap<T>(value: T): T {
return value
}
const a = wrap(10) // T 被推导成 number,所以 a: number
const b = wrap('hello') // T 被推导成 string,所以 b: string
理解:
- value 的类型 = T
- 返回值类型 = T
- 所以“传什么类型进来,就返回什么类型出来”
(2)多个参数共享同一个 T:要求它们类型一致
function first<T>(a: T, b: T): T {
return a
}
first(1, 2) // ✅ T = number
first('a', 'b') // ✅ T = string
first(1, 'a') // ❌ 报错:T 不可能同时是 number 和 string
理解:这里 T 出现在 a 和 b 上,表示 a 和 b 必须同类型。
(3)数组/容器里的 T:表示“元素类型”
function head<T>(list: T[]): T | undefined {
return list[0]
}
head([1, 2, 3]) // T = number
head(['a', 'b']) // T = string
理解:T[] 说明“这是个数组,数组元素类型是 T”。
疑问:数组里面的元素要一模一样吗?不一样可以吗?
(4)有多个类型变量:每个代表不同角色
function pair<T, U>(a: T, b: U): [T, U] {
return [a, b]
}
pair(1, 'x') // [number, string]
理解:T 和 U 是两个独立的占位符,分别对应不同参数类型。
疑问:那意思就是说
pair(0,false)
pair('111',false)
pair(0,'123')
pair(0,88)也可以吗?
5)带约束的 T extends ...:限制 T 的范围
function len<T extends { length: number }>(x: T) {
return x.length
}
理解:T 仍然是占位符,但它必须“至少有 length:number”。
疑问:len(2.length)可以吗