TypeScript泛型

772 阅读2分钟
  • 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
  • 泛型T作用域只局限于函数内部使用

泛型函数

  • 首先,我们实现一个函数createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值
//平常写法
function createArray(length: number, value: any): Array<any> {
  let result: any = [];
  for (let i = 0; i < length; i++) {
    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; i< length; i++){
		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;i<args.length; i++){
        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; i < this.list.length; i++){
        	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; i < length; i++){
		result[i] = value;
	}
    return result;
}
let result = createArray(3,'x','y')
let result = createArray(3,'x',1);//第三个参数报错,因为通过第二个参数可以判定为T为string,所以第三个参数也应该为string

泛型的约束

  • 在函数中使用泛型的时候,由于预先不知道具体的类型,所以不能随意访问相应类型的属性或方法
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泛型类型别名

  • 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不是创建新的名字,例如报错信息就不会使用别名
  • 类型别名不能被extendsimplements,这时我们应该尽量使用接口代替类型别名
  • 当我们需要使用联合类型或者元祖类型的时候,类型别名会更合适