typescript教程:泛型函数(形参泛型)

介绍

下面函数是 TypeScript 泛型函数 的基础代码,核心作用是:定义一个可以接收任意类型值、并保留类型信息的引用函数(对标 Vue3 中的 ref 响应式引用)。

// 定义一个泛型函数 myRef,T 是泛型类型参数
function myRef<T>(value: T) {

}

代码解释

逐行拆解:

  1. function myRef:声明一个名为 myRef 的函数
  2. <T>:泛型类型参数(可以理解为「类型占位符」),T 是自定义名称,也可以写成 <Type>、<V>
  3. (value: T):函数参数 value 的类型 = 泛型 T,传入什么类型的值,T 就自动变成什么类型
  4. 目前函数体为空

概念:什么是泛型?

用一句话解释:
泛型 = 不提前写死类型,让函数「复用逻辑 + 保留类型」,适用于任意数据类型。

对比普通函数 vs 泛型函数:

  • 普通函数:只能固定一种类型(比如只能传数字/字符串)
  • 泛型函数:传字符串 → 自动识别字符串类型;传对象 → 自动识别对象类型,类型不会丢失

应用场景

一般常见参数约束场景:不用泛型只能用 any,参数随便传、线上隐藏大量 bug。

使用泛型,会让函数调用更加安全:

  • 约束数组每一项的统一类型
  • 约束对象只能传合法 key
  • 约束批量修改的字段不能乱传
  • 约束回调函数的参数类型

例子1:通用数组处理

需求:遍历数组、打印每一项,只约束传入的数组元素类型

不用泛型(烂写法)

function printList(arr: any[]) {
  arr.forEach(item => console.log(item))
}

// 胡乱传,完全不校验
printList([1, 2, 3])
printList(['a', 'b'])
printList([1, '哈哈', true]) // 混合类型也不报错

泛型写法(只约束参数)

// <T> 只用来约束 参数 arr 的成员类型
function printList<T>(arr: T[]) {
  arr.forEach(item => console.log(item))
}

// 传入数字数组 → 参数强制只能是 number[]
printList<number>([1, 2, 3])
// printList<number>(['a', 2]) // ❌ 参数直接报错

// 传入字符串数组 → 参数强制只能是 string[]
printList<string>(['张三', '李四'])

✅ 关键点:
仅仅靠泛型约束「入参结构」,和返回值没有半点关系。


例子2:通用对象 key 取值(前端高频)

需求:传入一个对象、传入它的 key,约束 key 必须是对象身上合法属性

泛型参数版(纯参数约束)

// T 约束目标对象,K 约束对象的合法 key
function getObjKey<T, K extends keyof T>(obj: T, key: K) {
  console.log(obj[key])
}

const user = { name: '小明', age: 18 }

getObjKey(user, 'name') // ✅ 参数合法
getObjKey(user, 'age')  // ✅ 参数合法
getObjKey(user, 'sex')  // ❌ 参数直接红线:user 没有 sex 属性

这里:

  • T 约束第一个参数 obj
  • K 约束第二个参数 key
    全程只管入参合法性,函数内部只是打印,无返回值约束。

例子3:通用批量赋值函数

需求:给目标对象,批量修改字段,约束传入的修改字段必须匹配对象结构

function updateForm<T>(form: T, patch: Partial<T>) {
  // 内部逻辑:合并赋值,不用管返回
  Object.assign(form, patch)
}

const loginForm = {
  username: '',
  password: ''
}

// ✅ patch 参数只能是 username / password
updateForm(loginForm, { username: 'admin' })

// ❌ 报错:phone 不是表单合法字段
updateForm(loginForm, { phone: '111' })

核心:
Partial<T> 只用来约束第二个入参,和返回值无关。


例子4:通用过滤函数(纯入参约束)

// 约束 list 数组元素类型
function filterList<T>(list: T[], filterFn: (item: T) => boolean) {
  list.filter(filterFn)
}

// 数字数组 + 数字判断逻辑,参数强绑定
filterList<number>([10, 20, 30], (item) => item > 15)

// ❌ 第二个回调参数 item 会被锁死为 number,不能乱用字符串方法
filterList<number>([10, 20], (item) => item.includes('1'))

总结

  1. <T> 是泛型参数,代表「任意类型」,由传入值自动决定
  2. 泛型函数 = 逻辑复用 + 类型保留
  3. myRef<T> 接收任意类型值,返回 { value: T } 引用对象
  4. 广泛用于响应式、状态管理、通用工具函数

原文出处:/show_1GW3DN2VpqmY.html