Typescript学习之泛型的理解
泛型 官网介绍
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。
组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,
这在创建大型系统时为你提供了十分灵活的功能。
个人理解的泛型
泛型是指广泛的类型,多种类型或者任意类型,是一个类型参数或类型变量。
下面是一些泛型案例和理解,以及一些其他概念
泛型初探 为什么需要泛型以及泛型的演变由来
当一个类型变量或类型参数不确定时,希望适用于多个类型,但又不希望定义为any。
下面定义了一个getData函数,T是一个类型变量,参数data和返回值都属于这种类型变量。
function getData< T > ( data: T ) : T {
return data
}
再比如说,下面定义一个求和函数,参数x和y是数字类型,返回值也是数字类型
function funSums ( x : number, y : number) : number {
return x + y
}
假设现在需要一个方法,传入一个数组,返回一个数组
interface Arr extends Array {
[ index: number] : {
name : string
serialnumber : number
data : string
}
}
let arr : Arr = [
{ name : '嘻嘻嘻' , serialnumber : '3' , data : '' } ,
{ name : '嘿嘿嘿' , serialnumber : '4' , data : '' } ,
{ name : '哇哇哇' , serialnumber : '2' , data : '' } ,
{ name : '哈哈哈' , serialnumber : '1' , data : '' } ,
]
function getNewArray ( list : Arr) : Arr {
list. sort ( ( a, b ) => {
return a. serialnumber > b. serialnumber ? 1 : - 1
} )
return list
}
let arrList = getNewArray ( arr)
上述代码用Arr接口定义了一个对象数组,并用arr实现了这个接口,getNewArray函数接收一个对象数组,经过排序后返回该数组,只改变顺序,不改变对象结构。如果希望传入的是任意类型的数组,经过排序,返回该数组,下面来实现一下。
interface Arr extends Array {
[ index: number] : {
name : string
serialnumber : number
data : string
}
}
let arr : Arr = [
{ name : '嘻嘻嘻' , serialnumber : '3' , data : '' } ,
{ name : '嘿嘿嘿' , serialnumber : '4' , data : '' } ,
{ name : '哇哇哇' , serialnumber : '2' , data : '' } ,
{ name : '哈哈哈' , serialnumber : '1' , data : '' } ,
]
function getNewArray< U > ( list: U [ ] ) : U [ ] {
list. sort ( ( a, b ) => {
return a. serialnumber > b. serialnumber ? 1 : - 1
} )
return list
}
}
let arrList = getNewArray< Arr> ( arr)
上述代码用一个U来做类型变量,使得这个函数可以接收任意类型的参数,并返回处理后的参数。
定义了泛型函数后,可以用两种方法使用。
function identity< T > ( arg: T ) : T {
return arg;
}
第一种是,传入所有的参数,包含类型参数:
let output = identity< string> ( "myString" ) ;
第二种方法更普遍。利用了类型推论 – 即编译器会根据传入的参数自动地帮助我们确定T的类型:
let output = identity ( "myString" ) ;
官网案例
function loggingIdentity< T > ( arg: T [ ] ) : T [ ] {
console. log ( arg. length) ;
return arg;
}
笔记
如上所述,你可以这样理解loggingIdentity的类型:泛型函数loggingIdentity,
接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型是T的数组。
如果我们传入数字数组,将返回一个数字数组,因为此时 T的的类型为number。
这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性。
使用带有调用签名的对象字面量来定义泛型函数,类型参数实参和形参命名可以不一致,位置和数量一致就可以。
function identity< T > ( arg: T ) : T {
return arg;
}
let myIdentity : { < U > ( arg: U ) : U } = identity;
泛型接口
interface GenericIdentityFn {
< A > ( arg: A ) : A ;
}
function identity< T > ( arg: T ) : T {
return arg;
}
let myIdentity : GenericIdentityFn = identity;
我们可能想把泛型参数当作整个接口的一个参数。 这样我们就能清楚的知道使用的具体是哪个泛型类型(比如: GenericIdentityFn 而不只是GenericIdentityFn )。 这样接口里的其它成员也能知道这个参数的类型了。
interface GenericIdentityFn < A > {
( arg: A ) : A ;
}
function identity< T > ( arg: T ) : T {
return arg;
}
let myIdentity : GenericIdentityFn< number> = identity;
泛型类 泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
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; } ;
泛型约束
下面定义了一个Lengthwise 接口,约定了一个number类型的length属性,loggingIdentity函数的类型参数T继承了这个接口,如果参数没有length属性就会报错,这个就是泛型约束。
interface Lengthwise {
length : number;
}
function loggingIdentity< T extends Lengthwise > ( arg: T ) : T {
console. log ( arg. length) ;
return arg;
}
在泛型约束中使用类型参数
function getProperty ( obj : T , key : K ) {
return obj[ key] ;
}
let x = { a : 1 , b : 2 , c : 3 , d : 4 } ;
getProperty ( x, "a" ) ;
getProperty ( x, "m" ) ;
上述声明一个类型参数T,且它被另一个类型参数K所约束。
比如,现在我们想要用属性名从对象里获取这个属性。
并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束。
在泛型里使用类类型
function createFunc< T > ( Func: { new ( ) : T } ) : T {
return new Func ( )
}
一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。
class BeeKeeper {
hasMask : boolean;
}
class ZooKeeper {
nametag : string;
}
class Animal {
numLegs : number;
}
class Bee extends Animal {
keeper : BeeKeeper;
}
class Lion extends Animal {
keeper : ZooKeeper;
}
function createInstance< A extends Animal > ( c: new ( ) => A ) : A {
return new c ( ) ;
}
createInstance ( Lion) . keeper. nametag;
createInstance ( Bee) . keeper. hasMask;
结尾
以上就是关于Typescript的泛型理解和总结,有错误和补充的话,欢迎指正,会修改,谢谢。