深入理解TS类型系统中的泛型(上篇)
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
序言
作为TS 的核心之一泛型,总是让人有很多不解的地方,那么究竟什么是泛型?有什么作用?如何使用?今天我们带着问题一一探寻
泛型的定义
TS 中,泛型表示 泛指某一个类型, 开发者可以指定一个表示类型的变量,用他来作为实际类型的占位符 ,用尖括号来包裹类型变量<T>
。
泛型的作用
用作创建可重用的组价,从而让一个组件可以支持多种数据类型,它可以作用在接口,类,函数或者类型别名上。
普通定义
我们通过一个例子来体验一下泛型的作用
//我们在TS 中定义一个 infoCenter 用于展示用户的信息
function infoCenter (age: number,name:string) : string{
return `我是${name},我${age}岁`;
}
console.log(infoCenter(24,'coolFish')) // "我是coolFish,我24岁"
上例中,我们定义了infoCenter
的方法,入参我们限定了age 为 number,名字为string,使该函数仅可用于该原始类型number,string
。 所以该函数并不是通用的,例如,name限定为string,不能使用number,。虽然我们可以把 string 换成 any,但这样的话,我们失去了定义应该返回哪种类型的能力,并且在这个过程中使编译器失去了类型保护的作用。
泛型定义
我们如果要让 userCenter 可以适用于任意的类型,那就需要用到泛型
function infoCenter (age : T,name : U) : U{
return `我是${name},我${age}岁`;
}
console.log(infoCenter<Number, string>(24,'coolFish')) // "我是coolFish,我24岁"
//我希望name 为Number
console.log(infoCenter<Number, Number>(24, 6666)) // "我是6666,我24岁"
这样我们就能灵活的配置,我们的入参用什么类型的参数。
小结:
泛型参数就像函数中的类型参数一样,都是一个占位符,函数中是占 入参值,泛型占的类型,在输入时,会自动分配到相应的位置,就像上例,Number 会分配给 T, string 会分配给 U。
泛型接口
要解决函数中返回多种类型对象的问题,我们可以创建一个用于 infoCenter 的通用 infoCenters
接口
interface Identities<T, U> {
age: T,
name: U
}
定义完infoCenters
接口后,我们可以把该接口作为 infoCenter 的返回值类型。
function identity<T, U> (age: T, name: U): Identities<T, U> {
console.log(age + ": " + typeof (age));
console.log(name + ": " + typeof (name));
let identities: Identities<T, U> = {
age,
name
};
return identities;
}
console.log(identity(25, "coolFish"));
// 25: number
// coolFish: string
// {age: 68, name: "coolFish"}
由此,我们知道,泛型接口不仅仅可以作用于函数,还可以作用于返回值。同样,还可以作用在类里面
泛型类
泛型接口约束的是方法,泛型类约束是类。使用的话也简单,在类的后面使用<T,...>
的语法定义任意多个类型变量。
interface GenericInterface<U> {
value: U
getIdentity: () => U
}
class IdentityClass<T> implements GenericInterface<T> {
value: T
constructor(value: T) {
this.value = value
}
getIdentity(): T {
return this.value
}
}
const myNumberClass = new IdentityClass<number>(25);
console.log(myNumberClass.getIdentity()); // 25
const myStringClass = new IdentityClass<string>("coolFish!");
console.log(myStringClass.getIdentity()); // coolFish!
我们注意到,这和实现接口一样,类里面得实现,泛型类里定义的内容。
推荐阅读
-
轻松理解 TypeScript 中的泛型 T 与 any 类型的不同之处
-
玩转现代TypeScript的高阶指南:深入理解泛型与类型操作艺术
-
从入门到精通:TS(类型系统)的泛型实战指南
-
玩转 TypeScript:深入理解与实际运用中的泛型机制
-
TypeScript新手指南(9):理解TS中的泛型、泛型函数、泛型类和泛型接口
-
在 TypeScript 中,理解任意类型(type any)与泛型的差异之处
-
升级技巧:深入理解TS的高级类型 - 泛型实例解析
-
理解 TypeScript 中的泛型和条件类型里的自动推断机制
-
深入理解TS类型系统中的泛型(上篇)
-
升级理解:TS里的类型assertion与泛型详解