:::warning
泛型是指在定义函数、接口或类的时候,
不预先指定具体的类型,而在使用的时候再指定类型的一种特性
:::
在我们声明一个函数的时候,并且这个函数的入参可以是任意类型的时候,我们很难去做到确定返回的参数类型。
function echo(arg:any):any{return arg}// const result: any// 这里的result返回的类型还是any.const result = echo(123)
如何使用泛型来确定类型
// 我们可以使用<>符号,里面定义一个占位符,这个占位符可以是任意字段function echo<T>(arg:T):T{return arg}// 这个时候他的类型不再是any了// const result: 123const result = echo(123)// const result: trueconst result = echo(true)
function swap<T, U>(tuple: [T,U]): [U, T]{return [tuple[1], tuple[0]]}// const result: [number, string]const result = swap(['string',123])
总结
:::warning
其实泛型就相当于一个占位符或者说是一个变量,
在使用的时候,我们可以把定义好的类型像参数一样传入,
然后它原封不动的给我们输出回来
:::
泛型约束 extends
在函数内部使用泛型变量的时候,由于事先不清楚它是哪种类型,所以不能随意的操作它的属性或方法。
:::warning 所谓的泛型约束,其实就是规定传入的类型必须按照我们规定的写法来传入 :::
例如
// 因为泛型T,不一定包含属性lengthfunction echoWithArr<T>(arg: T): T{console.log(arg.length) // 会报错 类型“T”上不存在属性“length”return arg}// 改造, 但是这种写法只能传数组function echoWithArr<T>(arg: T[]): T[]{console.log(arg.length) // 这样就没问题了return arg}const arrs = echoWithArr([1,2,3])// 所以我们可以对泛型进行一个约束,让他只能传入有length的参数interface IWithLength {length: number}// 我们可以< 变量 extends 类型 >function echoWithLength<T extends IWithLength>(arg: T): T{console.log(arg.length)return arg}// 只要有length属性,都可以,所以这也是鸭子类型的概念const str = echoWithLength('str')const obj = echoWithLength({ length:10, width:10})const arr2 = echoWithLength([1,2,3])// 报错,类型“number”的参数不能赋给类型“IWithLength”的参数const num = echoWithLength(13)
泛型与类和接口
当我们在类里面定义一些方法,并且这些方法只有某些类型才有。那么我们在使用该类的方法是有可能会报错,并且ts在编译过程中无法获取错误
:::warning
像下面例子,我们分别添加了数值和字符串,但是我们都调用了toFixed方法,因为toFixed是属于number的方法。
所以str调用一定会报错,但是在下面的例子中,ts无法检测报错,只有在运行时才能发现。
:::
例如
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.log(queue.pop().toFixed())console.log(queue.pop().toFixed())
改造一下
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(1);// 类型“string”的参数不能赋给类型“number”的参数。queue.push('str') // 报错console.log(queue.pop().toFixed())console.log(queue.pop().toFixed())
接口和泛型
:::warning 我们的接口interface也可以使用泛型变得更灵活 :::
// 我们这种写法可以自定义传值,更加灵活interface KeyPair<T, U> {key: T;value: U;}let kp1: KeyPair<number, string> = { key:1, value:'str'}let kp2: KeyPair<string, number> = { key:'str', value:1}// 我们之前定义的数字类型数组let arr:number[] = [1,2,3]// 如果使用泛型和ts内置的interface-numberlet arrTwo: Array<number> = [1,2,3]
