泛型
泛型(generic)是 TypeScript 中一个非常重要的特性, 它允许我们编写可以处理多种类型的通用
代码, 同时还能保持类型的安全性。
什么是泛型:可以传递类型的参数
泛型就是可以携带类型的变量
ts
泛型参数 规范:要求都是 大写字母:K、T、V、P、S、R为泛型
shell
1. 泛型接口
2. 泛型类
3. 泛型约束
泛型背景
下面创建一个函数,
实现功能: 根据指定的数量 count
和数据 value
, 创建一个包含 count
个 value
的数组
不用泛型的话,这个函数可能是下面这样:
ts
function createArray (count:number,value:any):any[]{
const arr:any[] = []
for (let index = 0; index < count; index++) {
arr.push(value)
}
return arr
}
const arr01 = createArray(3,'hello')
const arr02 = createArray(3,100)
console.log(arr01[0].split('')) //运行不报错,但编码时没有提示
console.log(arr02[0].toFixed(3)) //运行不报错,但编码时没有提示
console.log(arr02[0].split('')) //运行报错,但编码时没有提示错误
通过泛型函数可以实现在编码时提示
ts
function createArray <P>(count:number,value:P):P[]{
const arr:P[]= []
for (let index = 0; index < count; index++) {
arr.push(value)
}
return arr
}
const arr03 = createArray<string>(3,'hello')
const arr04 = createArray<number>(3,100)
console.log(arr03[0].split(''))
console.log(arr04[0].toFixed(1))
console.log(arr04[0].split('')) //error 类型“number”上不存在属性“split”
泛型参数
可以传递类型的参数,称之泛型参数
tsx
# 泛型参数,要求都是 大写字母:K、T、V、P、S、R
function createArr<K>(num: number, item: K): K[] {
let arr: K[] = [];
for (let i = 0; i < num; i++) {
arr[i] = item;
}
return arr;
}
console.log(createArr<string>(3, 'a')); // ['a','a','a']
console.log(createArr<number>(2, 99)); // [99,99]
多个泛型参数的函数
一个函数可以定义多个泛型参数
ts
function createArray <T,P> (a: T, b: P): [T, P] {
return [a, b]
}
const result = createArray<string, number>('abc', 123)
console.log(result[0].length)
console.log(result[1].toFixed())
泛型接口
什么时候使用:如果一个对象的类型是实时变化的,就需要泛型作为参数来定义这个对象的类型。
在定义接口时, 如果接口中对象类型不确定,就需要给接口中的属性或方法定义为泛型类型;在使用接口时, 再指定具体的泛型类型(传参,这个参数是一个接口类型)。
ts
// 用泛型来限定接口类型(接口传一个泛型来限定接口的类型)
interface IResponse<T> {
code: number;
msg: string;
data: T
}
interface IBook {
id: string;
name: string;
author: string;
}
interface ITodo {
id: string;
title: string;
isDone: boolean;
}
let data1: IResponse<IBook> = {
code: 200,
msg: '成功',
data: {
id: 'adfd123',
name: '葵花宝典',
author: '东方不败'
}
}
let data2: IResponse<ITodo> = {
code: 200,
msg: '获取数据成功',
data: {
id: '123',
title: '吃饭',
isDone: true
}
}
泛型类
在定义类时, 为类中的属性或方法定义为泛型类型 ;在创建类的实例时, 再指定特定的泛型类型(传参,参数是一个接口)
ts
// 泛型类:用泛型限定类
class Container<T>{
//用于储存数据
store: T[];
constructor(store: T[]) {
this.store = store;
}
}
let books = new Container<IBook>([
{ id: 'ab123', name: '西游记', author: '吴承恩' },
{ id: 'sx23', name: '三国演义', author: '罗贯中' }
])
let todos = new Container<ITodo>([
{ id: 'sfre1', title: 'chifan', isDone: true }
])
泛型约束
如果我们直接对一个泛型类型参数取 length
属性, 会报错, 因为这个泛型根本就不知道它有这个属性
ts
// 没有泛型约束
function fn <T>(x: T): void {
// console.log(x.length) // error 需要保证x有length属性,如何保证x有length属性
}
我们可以使用泛型约束来实现
ts
// 如何保证x有length属性,=> 让x的类型为泛型T的类型,指定泛型T必须拥有length属性。
// 定义一个接口,这个接口有length属性
interface Lengthwise {
length: number;
}
/**
* 前提条件:泛型是一种特殊类型的接口
*/
// 让泛型T继承这个接口,那么泛型T就有了length属性,
// 通过(x: T)这样就限定x必须要有length属性
function fn2<T extends Lengthwise>(x: T): void {
console.log(x.length)
}
fn2('abc')
// fn2(123);
fn2([1,2,3])