TypeScript函数中如何使用泛型并获取泛型T的类型?
嘿,刚好对TypeScript泛型这块熟得很,我来给你一步步讲清楚函数里怎么用泛型,以及怎么获取泛型参数T的具体类型!
一、函数中使用泛型的基础玩法
泛型的核心是让函数能适配多种类型,同时保留类型检查,不用写一堆any。
1. 最基础的泛型函数定义
在函数名后面加<T>(T是约定俗成的泛型参数名,你换成U、V也没问题),然后在参数、返回值里用T指代这个类型:
// 一个返回传入值的通用函数 function identity<T>(arg: T): T { return arg; }
使用的时候有两种方式:
- 显式指定类型:
const numResult = identity<number>(123); - 让TypeScript自动推断:
const strResult = identity("hello");(TS会自动把T推断成string)
2. 带约束的泛型函数
如果想限制T的范围,比如必须包含某个属性,可以用extends:
interface HasId { id: number; } // T必须是HasId的子类/实现类 function getEntityById<T extends HasId>(entities: T[], id: number): T | undefined { return entities.find(item => item.id === id); } // 传入符合HasId的数组,TS会自动推断T的具体类型 const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]; const foundUser = getEntityById(users, 1); // foundUser的类型是{ id: number; name: string; } | undefined
二、获取泛型参数T的具体类型
这里要分编译时(类型层面)和运行时两种场景,因为TypeScript的类型会在编译成JS后被擦除,两者的处理方式完全不同。
1. 编译时提取T的类型
在类型层面,TypeScript提供了很多工具类型,或者你可以自己写类型工具来提取T:
从泛型函数中提取T
比如想拿到上面identity函数的参数/返回值类型(也就是T):
// 获取identity函数的第一个参数类型 type IdentityArgType = Parameters<typeof identity>[0]; // 获取identity函数的返回值类型 type IdentityReturnType = ReturnType<typeof identity>; // 如果我们显式调用identity<number>(123),那这两个类型都会是number
自定义类型工具提取泛型参数
如果有一个泛型接口/类型,想把它的泛型参数抽出来,可以用infer关键字:
// 定义一个工具类型,用来提取泛型类型的参数 type ExtractGenericParam<T> = T extends GenericContainer<infer U> ? U : never; // 一个泛型容器接口 interface GenericContainer<T> { value: T; } // 提取GenericContainer<string>的泛型参数 type ExtractedType = ExtractGenericParam<GenericContainer<string>>; // ExtractedType就是string
2. 运行时获取T的类型
因为编译时类型擦除,运行时根本没有T这个概念,所以我们得用JavaScript本身的手段来判断:
判断基本类型
用typeof操作符:
function getRuntimeType<T>(arg: T): string { switch (typeof arg) { case "string": return "string"; case "number": return "number"; case "boolean": return "boolean"; // 其他基本类型... default: return "object/function/unknown"; } }
判断引用类型
用instanceof操作符,适用于类实例:
class Cat { meow() {} } class Dog { woof() {} } function checkAnimalType<T>(animal: T): string { if (animal instanceof Cat) { return "Cat"; } else if (animal instanceof Dog) { return "Dog"; } return "Unknown Animal"; }
手动传递类型标记
如果需要更精确的类型信息(比如区分不同的对象类型),可以在调用函数时额外传一个类型标识:
function processItem<T>(item: T, type: "user" | "product"): void { if (type === "user") { // 这里可以安全地把item当作User类型处理 console.log("Processing user:", (item as User).name); } else { console.log("Processing product:", (item as Product).sku); } } processItem({ id: 1, name: "Alice" }, "user");
总的来说,泛型让你的函数更灵活复用,编译时靠TypeScript的类型工具就能轻松提取T的类型,运行时则要借助JS的原生判断或者手动传递类型信息来实现。
内容的提问来源于stack exchange,提问作者kirno
相关产品推荐
相关产品推荐

