指的是去定义函数,接口,类的时候没有去定义具体类型,我们在使用的时候再去定义指定类型的这一种特征。
以函数为例,泛型 就是我们在声明一个函数的时候不去指定一个类型,等我们调用的时候再传入一个具体的类型,这样做的目的是极大程度的复用我们的代码。
比如 定义一个创建 number 类型和 string 类型数组的方法:
不使用泛型:
// 定义一个创建 number 类型的方法
function createNumberArray (length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
// 定义一个创建 string 类型的方法
function createStringArray (length: number, value: string): string[] {
const arr = Array<string>(length).fill(value)
return arr
}
const numArr = createNumberArray(3, 100)
const strArr = createNumberArray(3, 'foo')
使用泛型:
把类型用一个泛型参数 T 表示,把函数当中不明确类型用 T 去代表,在使用的时候再传递具体类型。如下:
function createArray<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const numArr = createArray<number>(3, 100)
const strArr = createNumberArray<string>(3, 'foo')
其实 Array 是一个泛型类,在 typescript 中去定义这个 Array 类型时,它不知道我们使用它去存放什么样类型的数据,所以它就使用泛型参数,在我们去调用的时候再传入具体类型,这是一个泛型提现。
总的来说,泛型就是在我们定义的时候把不明确的类型,变成一个参数,在我们使用的时候再传递这样的一个类型参数。
常用的泛型变量
- T:代表Type,在定义泛型时通常用作第一个类型变量名。
- K:表示对象中的键类型
- V:表示对象中的值类型
- E:表示元素类型
泛型的基本使用
处理函数参数,统一输入和输出的类型
我们在使用可以有两种方式指定类型
- 定义要使用的类型
- TS 类型推断,自动导出类型
使用 type定义函数类型
使用 interface定义函数类型
泛型参数默认类型
语法:<T = default type>
// 使用 type 定义了 fn 函数,fn 函数的泛型默认是 number
type fn<T = number> = (arg: T) => T
泛型约束
- 约束函数参数类型
// 定义一个函数打印参数的 length
function printLnegth<T>(arg:T) {
console.log(arg.length) // 这样写会报错,因为泛型 T 并没有 length 属性
}
这时可以通过 interface 来约束泛型
interface LengthProps {
length: number
}
function printLnegth<T extends LengthProps>(arg:T) {
console.log(arg.length)
}
其中<T extends LengthProps>,让泛型继承了接口 LengthProps,使得泛型T 具有了 length属性,从而使得函数参数具有了 length属性
- 约束接口
interface KeyValue<T, U> {
key: T,
value: U
}
const k1: KeyValue<number, string> = {key: 123, value: 'zhangSan'}
cosnt k2: KeyValue<string,number> = {key: 'zhangSan', value: 123}
- 约束数组
// 之前定义数组
const arr1: number[] = [1,2,3]
// 通过泛型约束数组
const arr2: Array<number> = [1,2,3]
泛型工具类型
在TS中内置了一些常用的工具类型, 用来简化我们TS中的一些常见操作
这些泛型工具类型都是基于泛型实现的, 并且是内置的, 也可以直接在代码中使用
Partial(可选)
我们可以使用Partial<T>来构造或者创建一个类型, 将T的所有属性都设置为可选的
通过上面的实例, 可以发现, indexProps中的id和children就变成可选的了
但是生成的类型别名, 并不影响Props接口, 他只是创建了一个新的类型
Readonly(只读)
Readonly<Props>是用来构造一个类型, 将Props中的所有属性全部变成只读的
将上面的代码修改成readonly之后, 我们就不可以修改id的值, 因为他是只读的
Pick
Pick<T, K>是从T中选择一组属性来构造新类型
Pick相比于前两个工具类型还是有区别的
Pick工具类型有两个类型变量: 第一个表示选择谁的属性, 第二个选择哪几个类型
传入的属性名只能是第一个类型变量中的属性, 我们比如传入了id和children, 后面构造出来的indexProps就只有id和children属性类型了
Record
Record<K,T>构造一个对象类型, 属性键为K, 属性类型为T
Record工具类型有两个类型变量, 第一个表示对象有哪些属性, 第二个表示对象属性的类型
首先我们创建的obj对象有两个属性, 分别是a和b, 属性值要求是字符串数组string[]