为什么要用泛型
- 定义时就限制类型
只能传入number类型,无法传入string等类型function echo(arg:number):number{ return arg }
const result = echo(2)
- 采用any
是可以支持传入任何类型,可传入与返回的类型可以不一致。比如我们输入个number类型,我们只知道任何类型的值都有可能返回function echo(arg:any):any{ return any }
泛型
定义
在定义函数,接口或类时,不预先指定具体类型,而是在使用的时候动态填入确定类型值
使用
在函数名后加上,其中T可以换成任意字符。T帮助捕获传入的类型(比如 number),之后我们就可以在参数以及返回值里用这个类型T,就达到了传入类型与返回类型一致的效果
示例1:
function echo<T>(arg:T):T{
return any
}
const result = echo(123)
示例2
function swap<T,U>(tuple:[T,U]):[U,T]{
return [tuple[1],tuple[0]]
}
const s = swap(["23",23])
约束泛型
为什么会有约束泛型
function echoWithLen<T>(arg:T):T{
console.info(arg.length) // Error: T doesn't have .length
return arg;
}
报错的原因是:T代表任意类型,所以使用这个函数的人可能传入boolean类型,而boolean类型是没有length属性的
改成:
function echoWithArr<T>(arg:T[]):T[]{
console.info(arg.length)
return arg;
}
const arr = echoWithArr([1,2,3])
const arr2 = echoWithArr([1,2,"3"]) //T变成了number|string
// const arr3 = echoWithArr('str') //string实际上也有length属性,却会报错,所以这种定义方式有问题
采用interface extends
interface IWithLength {
length:number
}
function echoWithArr2<T extends IWithLength>(arg:T):T {
return arg
}
const arrWith = echoWithArr2([1,2,3])
const arrWith2 = echoWithArr2('str')
// const arrWith3 = echoWithArr2(23) //不可以,因为number没有length属性
泛型在对象上的使用
interface KeyPair<T,U> {
key:T,
value:U
}
let kp1:KeyPair<number,string> = {key:23,value:"23"}
let kp2:KeyPair<string,number> = {key:"23",value:23}
Array<类型>就是这种用法
let n:number[] = [2,3,4]
let n2:Array<number> = [2,3,4]
泛型在函数上的使用
interface IPlus2<T> {
(a:T,b:T):T
}
function plus2(a:number,b:number) :number {
return a+b;
}
function connect(a:string,b:string) :string {
return a+b;
}
const p2:IPlus2<number> = plus2
const c2:IPlus2<string> = connect
泛型在类上的使用
不使用typescript
class Queue {
private data = []
push(item) {
return this.data.push(item)
}
pop(){
return this.data.shift()
}
}
const queue = new Queue()
queue.push(1)
queue.push("str")
console.info(queue.pop().toFixed())
// console.info(queue.pop().toFixed()) //运行时才会报错
使用typescript基本类型校验
class Queue {
private data = []
push(item:number) {
return this.data.push(item)
}
pop():number{
return this.data.shift()
}
}
const queue = new Queue()
queue.push(1)
// queue.push("str") //会报错,起到了限制作用
console.info(queue.pop().toFixed())
使用泛型类
上面的起到了只允许传入number类型,但如果要弄个允许加入字符串,就得重新定义个类,这不合理
class Queue<T> {
private data = []
push(item:T) {
return this.data.push(item)
}
pop():T{
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(3)
console.info(queue.pop().toFixed()) //3
const queueStr = new Queue<string>()
queueStr.push("3")
console.info(queueStr.pop().indexOf("3")) //0