1 泛型的基础
泛型是指在定义函数或者接口的时候,不指定类型,只在使用的时候,才指定类型的一种特征,相当于一个占位符。
- 实例一,简单例子
// <T> 是指第一个参数的泛型
function echo<T>(arg: T): T {
return arg
}
const result1: boolean = echo(true)
const result2: number = echo(111)
- 实例二,两个参数互换位置
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const result3 = swap(['string', 123])
2 泛型约束
当函数使用泛型时,想要参数拥有 length 属性,如果是直接使用泛型限制,如下例子,则会报错:
function echoWithArr1<T>(arg: T): T {
console.log(arg.length) // Property 'length' does not exist on type 'T'
return arg
}
这时候,需要对参数进行约束,或者限定,解决方案一,如下:参数使用对象,因为对象就有了 length 属性,如下:
// arg: T[] => arg: Array<T>
function echoWithArr<T>(arg: T[]): T[] {
console.log(arg.length)
return arg
}
const arrs = echoWithArr([1, 2, 3])
这种方法不是太好,因为如果想要传入 string,或者对象就会报错;
解决方案二,使用接口约束泛型
:关键字 extends
interface IWithLength {
length: number
}
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length)
return arg
}
const str = echoWithLength('str')
const obj = echoWithLength({ length: 10, width: 10})
const arr2 = echoWithLength([1, 2, 3])
3 泛型,类和接口
- 类使用泛型
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) // 添加数字,拥有数字的方法
console.log(queue.pop().toFixed())
const queue2 = new Queue<string>()
queue2.push('str') // 添加字符串,拥有字符串的方法
console.log(queue2.pop().length)
- 接口使用泛型
interface KeyPair<T, U> {
key: T;
value: U;
}
let kp1: KeyPair<number, string> = { key: 123, value: "str" }
let kp2: KeyPair<string, number> = { key: 'test', value: 123 }
- 对象使用接口泛型
let arr: number[] = [1, 2, 3]
等价于
let arrTwo: Array<number> = [1, 2, 3] // Array 是接口,封装了很多方法
- 接口来描述函数的类型
interface IPlus<T> {
(a: T, b: T) : T
}
function plus(a: number, b: number): number {
return a + b;
}
const a: IPlus<number> = plus // 用接口来描 a 类型,使它等于 plus 函数类型
function connect(a: string, b: string): string {
return a + b
}
const b: IPlus<string> = connect // 用接口来描 b 类型,使它等于 connect 函数类型
4 相关示例
// 最简单类泛型
class DateList<T> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index];
}
}
new DateList<string>(['1']);
new DateList(['1']);
// 给泛型新增限制,必须有 name 属性
interface Item {
name: string;
}
class DateList<T extends Item> {
constructor(private data: T[]) {}
getItem(index: number): string {
return this.data[index].name;
}
}
new DateList<Item>([{ name: 'xiaoming' }]);
new DateList([{ name: 'xiaoming' }]);
// 泛型必须是 number 或者 string
class DateList<T extends string | number> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index];
}
}
new DateList<string>(['1']);
new DateList(['1']);
new DateList<number>([1]);
new DateList([1]);
// 函数使用泛型限制
const func: <T>(params: T) => T = <T>(params: T) => {
return params;
}