深入理解 TypeScript 的泛型机制
最编程
2024-07-27 22:02:35
...
泛型可以为封装的代码提升可重用性,不仅支持当前的数据类型,同时也能支持未来的数据类型。
泛型函数的基本使用
举个例子:创建一个函数,功能是返回值的类型与传入的参数类型相同。
下面是使泛型与不使用泛型的对比:
//不使用泛型,这样虽然也是可以满足需求,但是会丢失一些信息,比如传入一个数字,我们只能知道任何类型都是可能被返回的。
function getSameType(x:any):any{
return x;
}
//使用泛型,T 是类型变量,它可以帮助我们捕获输入的类型,之后再返回 T,可以确保传入的类型与返回类型是相同的。
function getSameType <T>(x:T):T{
return x;
}
//泛型的使用方式有两种,第一种是直接传入 T 的类型,第二种是利用编译器的类型推断自动帮我们确定 T 的类型
getSameType<string>("直接传入 T 的类型");
//利用编译器类型推论,某些情况可能无法推断出正确的类型,需要使用第一种方式,在一些复杂的情况下,这是可能出现的
getSameType("利用类型推断自动确定 T 的类型");
使用泛型变量
当我们使用泛型变量时,编译器要求你必须把参数当作 any 或者 所有类型来使用,否则会报错,如下所示:
function getSameType <T>(x:T):T{
//因为你可以能传入的是一个 number 类型,number 是没有.length 的
console.log(x.length); // Error: T doesn't have .length
return x;
}
如果需要使上面的例子不报错的话,那么需要把 T 当作 T 类型的数组即可
function getSameType <T>(x:T[]):T[]{
console.log(x.length); // 由于数组有 length 属性所以不会报错
return x;
}
泛型类型
泛型函数的类型和非泛型函数的类型没什么不同,只是一个类型参数在最前面****(arg: U) => U,像函数声明一样
function identity<T>(arg: T): T {
return arg;
}
//可以使用不同的泛型参数名,只要数量上和使用方式一致即可。
let myIdentity: <U>(arg: U) => U = identity;
泛型接口类型,只需要在接口名后加泛型即可。
interface interFan<T>{
(arg:T):T;
}
let obj:interFan<string> = function(x:T):T{
return x;
}
泛型类与泛型接口一致,只需要在类名称后加即可。但是泛型变量只属于类的实例部分,类有两个部分:静态部分和实例部分,静态部分如 construtor 构造函数无法使用泛型。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
泛型约束
之前我们说过,泛型变量 T,编译器要求我们必须把它当作 any 或者任意类型,但是为了我们使用具体的属性如 length,我们必须要保证至少有这个属性的话,我们需要使用泛型约束。
//泛型约束,让 T 继承接口,保证 T 必须符合接口 fanInter 来实现约束
interface fanInter{
length:number
}
function fanInter<T extends fanInter>(arg:T):T{
console.log(arg.length);
return arg;
}
//你们可能会好奇为什么这样可以通过接口的严格检测,因为我们多了个接口未定义的属性 value,泛型约束与接口的赋值声明不同,泛型约束是属于宽松型检测,只要有规定的属性即可,因为泛型约束的意义是为了使用某些属性时不会报错,并且可以得到一些信息。
fanInter({length: 10, value: 3});
泛型约束中使用类型参数
如果我们需要从一个对象中获取一个属性,并且确保属性就在这个对象上,那么就需要在两个类型之间进行约束
function getProperty(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: 必须是 x对象中的属性!
在泛型中使用类类型
//在泛型中使用类类型
class Animal {
numLegs: number;
}
class Bee extends Animal {}
class Lion extends Animal {}
//泛型约束为 Animal 并且返回 Animal类型
function createInstance<A extends Animal>(c: new () => A): A {
let obj = new c();
console.log(obj.numLegs)
return obj ;
}
createInstance(Lion).numLegs // success!
createInstance(Bee).numLegs // success!
上一篇: TypeScript 初级教程 - 07章:理解与运用泛型
下一篇: TS 泛型+装饰器
推荐阅读
-
深入理解Python的Traceback机制
-
深入理解微服务架构:Soul微服务网关的数据同步机制
-
深入理解Spring事务的运作机制
-
从入门到精通:深入理解socket的 heartbeat机制
-
深入理解Core SignalR的重连与心跳检测机制
-
深入理解Netty的 heartbeat 机制
-
多元回归分析:理解相关关系并预测结果 - 一、多元回归分析旨在研究自变量X与因变量Y之间的关联,以揭示Y形成的机制,并利用X进行预测。共有五种常见的回归分析方法,包括线性回归、0‐1回归(逻辑回归)、定序回归、计数回归和生存回归,它们的划分依据是因变量Y的不同类型。因变量还可分为连续数值型变量等多种类别。
-
理解事件委托:深入探索事件的传播机制
-
全面解析数据库锁:共享锁、排他锁、更新锁、意向锁和计划锁,让你深入理解锁的作用机制
-
深入理解InnoDB引擎中的意向锁机制