- 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
- 泛型T作用域只局限于函数内部使用
泛型函数
- 首先,我们实现一个函数
createArray
,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值
//平常写法
function createArray(length: number, value: any): Array<any> {
let result: any = []
for (let i = 0
result[i] = value
}
return result
}
let result = createArray(3,'x')
console.log(result)
//泛型写法
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = []
for(let i = 0
result[i] = value
}
return result
}
let result = createArray<string>(3,'x')
类数组
- 类数组(Array-like Object)不是数组类型,比如
arguments
function sum(...args2:any[]){
let args:IArguments = arguments
for(let i=0
console.log(args[i])
}
}
sum(1,2,3,'4')
let root:HTMLElement | null = document.getElementById('root')
let children:HTMLCollection = root!.children
let childNodes:NodeListOf<ChildNode> = root!.childNodes
泛型类
class MyArray<T>{
private list:T[] = []
add(val: T){
this.list.push(val)
}
getMax():T{
let result:T = this.list[0]
for(let i = 1
if(this.list[i]>result){
result = this.list[i]
}
}
return result
}
}
let arr = new MyArray<number>()
arr.add(1)
arr.add(2)
arr.add(3)
console.log(arr.getMax())
泛型接口
interface Calculate {
<T>(a: T, b: T): T
}
let add:Calculate = function(a,b){
return a
}
add<number>(1,3)
interface Cart<T>{
list: T[]
}
let cart: Cart<string> = {
list:['1','2']
}
interface Cart<T>{
list:T[]
}
let cart:Cart<{name:string,price:number}> = {
list:[{name:'zhiweili',price:10}]
}
多个类型参数
- 泛型可以有多个
- 例:如何在不增加中间变量的情况下,交换二个变量的值
function swap<A,B>(tuple: [A,B]):[B,A]{
return [tuple[1],tuple[0]]
}
let result = swap<string,number>(['xiuli',18])
默认泛型类型
function createArray<T=number>(length:number, value:T, value2: T):Array<T>{
let result: T[] = []
for(let i = 0
result[i] = value
}
return result
}
let result = createArray(3,'x','y')
let result = createArray(3,'x',1)
泛型的约束
- 在函数中使用泛型的时候,由于预先不知道具体的类型,所以不能随意访问相应类型的属性或方法
function loagger1<T>(val:T){
console.log(val.length);//length报错,因为不知道T是什么类型,所以不能访问相应类型的方法
}
// ----
interface LengthWise {
length:Number
}
function logger<T extends LengthWise>(val: T){
console.log(val.length)
}
logger('xiuli')
泛型类型别名
interface
定义一个实实在在的接口,它是一个真正的类型
type
一般用来定义别名,并不是一个真正的类型
- 泛型类型别名可以表达更复杂的类型
type Cart2<T> = {list:T[]} | T[];
let c1:Cart2<string> = {list:['1']}
let c2:Cart2<string>=['1']
泛型接口vs泛型类型别名
- 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不是创建新的名字,例如报错信息就不会使用别名
- 类型别名不能被
extends
和implements
,这时我们应该尽量使用接口代替类型别名
- 当我们需要使用联合类型或者元祖类型的时候,类型别名会更合适