三块面板:TS 源码 / 写死的 tsc 报错样本(非现场运行)/ 可点跑的等价 JS。泛型 = 类型的参数,让返回类型跟着输入形状变,不像 any 那样把信息漏光。
any,再写成泛型// any 版:进去知道是 number[],出来啥都不知道
function firstAny(arr: any[]): any { return arr[0] }
const x = firstAny([1, 2, 3]) // x: any —— 丢了元素类型
// 泛型版:类型进函数又活着出来
function first<T>(arr: T[]): T { return arr[0] }
const a = first([1, 2, 3]) // T 推断成 number,a: number
const b = first(['x', 'y']) // T 推断成 string,b: string
a.toUpperCase() // ✗ a 是 number,没有 toUpperCase
extends:给 T 划范围才能访问成员function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b // ✓ 约束保证有 length
}
longest('abc', 'a') // ✓ string 有 length
longest(1, 2) // ✗ number 没有 length,被约束挡下
T extends { length: number } 既让函数内部敢访问 length,又在调用点拦住不合格的实参——约束是泛型的“边界”两面。function box<T = string>(v: T): { value: T } { return { value: v } }
box('a') // T = string
box(42) // T = number(实参优先于默认)
// 用泛型:输入类型与输出类型之间存在“形状依赖”
function identity<T>(v: T): T { return v } // 给啥类型就按同样形状返回
function pair<A, B>(a: A, b: B): [A, B] { return [a, b] }
// 别用泛型:结果与入参无关,或只是“几种固定情况之一”——那用联合类型
type Status = 'idle' | 'loading' | 'error' // 联合即可,别硬写成泛型