泛型函数是使用泛型的函数,它可以处理多种类型的参数,同时保持类型安全。泛型函数是代码复用的重要手段。
在函数名后添加 <T> 声明类型参数,然后在参数和返回值中使用这个类型。
function identity<T>(arg: T): T {
return arg
}
const str = identity<string>("hello")
const num = identity(123)
console.log(str)
console.log(num)
identity 函数接受一个 T 类型的参数,返回相同类型的值。调用时可以显式指定类型或让 TypeScript 推断。
泛型函数的类型定义需要包含类型参数。
type Identity<T> = (arg: T) => T
const identity: Identity<string> = (arg) => arg
console.log(identity("hello"))
function createIdentity<T>(): Identity<T> {
return (arg: T) => arg
}
const numberIdentity = createIdentity<number>()
console.log(numberIdentity(123))
Identity<T> 是一个泛型函数类型,描述了接受 T 返回 T 的函数。
泛型函数常用于数组操作,可以处理任意类型的数组。
function first<T>(arr: T[]): T | undefined {
return arr[0]
}
function last<T>(arr: T[]): T | undefined {
return arr[arr.length - 1]
}
function filter<T>(arr: T[], predicate: (item: T) => boolean): T[] {
return arr.filter(predicate)
}
const numbers = [1, 2, 3, 4, 5]
console.log(first(numbers))
console.log(last(numbers))
console.log(filter(numbers, n => n > 2))
const strings = ["a", "b", "c"]
console.log(first(strings))
console.log(filter(strings, s => s !== "b"))
这些函数可以处理数字数组、字符串数组或任何其他类型的数组。
泛型函数也可以用于对象操作。
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
obj[key] = value
}
const user = {
id: 1,
name: "张三",
email: "zhangsan@example.com"
}
console.log(getProperty(user, "name"))
setProperty(user, "name", "李四")
console.log(user.name)
keyof T 获取类型 T 的所有键的联合类型,K extends keyof T 确保 key 参数是有效的键。
泛型函数可以创建高阶函数,返回新的函数。
function createValidator<T>(rules: Partial<Record<keyof T, (value: any) => boolean>>) {
return (obj: T): boolean => {
for (const key in rules) {
const rule = rules[key]
if (rule && !rule(obj[key])) {
return false
}
}
return true
}
}
interface User {
name: string
age: number
}
const validateUser = createValidator<User>({
name: (value) => value.length > 0,
age: (value) => value >= 0 && value <= 150
})
console.log(validateUser({ name: "张三", age: 25 }))
console.log(validateUser({ name: "", age: 25 }))
console.log(validateUser({ name: "李四", age: 200 }))
createValidator 返回一个验证函数,可以根据规则验证对象。
泛型函数在异步编程中也很常用。
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url)
return response.json()
}
interface User {
id: number
name: string
}
async function main() {
const user = await fetchData<User>("https://api.example.com/users/1")
console.log(user.name)
}
fetchData 函数返回一个 Promise<T>,调用时指定期望的响应类型。
泛型函数可以与函数重载结合使用。
function convert(value: string): number
function convert(value: number): string
function convert<T extends string | number>(value: T): T extends string ? number : string
function convert(value: string | number): string | number {
if (typeof value === "string") {
return parseInt(value, 10)
}
return String(value)
}
const num = convert("123")
const str = convert(456)
console.log(typeof num)
console.log(typeof str)
重载签名提供了更精确的类型信息,条件类型让返回值类型与参数类型关联。
泛型函数在实际开发中有很多应用场景。
function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout>
return (...args: Parameters<T>) => {
clearTimeout(timer)
timer = setTimeout(() => fn(...args), delay)
}
}
function throttle<T extends (...args: any[]) => any>(
fn: T,
interval: number
): (...args: Parameters<T>) => void {
let lastTime = 0
return (...args: Parameters<T>) => {
const now = Date.now()
if (now - lastTime >= interval) {
lastTime = now
fn(...args)
}
}
}
const logMessage = (msg: string) => console.log(msg)
const debouncedLog = debounce(logMessage, 300)
const throttledLog = throttle(logMessage, 1000)
debouncedLog("消息1")
debouncedLog("消息2")
debouncedLog("消息3")
throttledLog("节流消息1")
throttledLog("节流消息2")
debounce 和 throttle 是通用的工具函数,可以包装任意函数。Parameters<T> 获取函数类型的参数类型。
泛型函数是 TypeScript 中代码复用的重要工具。通过类型参数,函数可以处理多种类型,同时保持类型安全。泛型函数可以用于数组操作、对象操作、高阶函数和异步编程。合理使用泛型函数可以减少代码重复,提高代码的可维护性。