泛型(Generics
) 是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
示例
假如我们需要一个 输入数字 => 返回数字 的函数
function echoValue(args: number): number {
return args
}
// ?正确
echoValue(1)
// ?错误
// Argument of type ‘string‘ is not assignable to parameter of type ‘number‘.
echoValue(‘1‘)
也需要一个 输入字符串 => 返回字符串 的函数
function echoValue(args: string): string {
return args
}
// ?正确
echoValue(‘1‘)
// ?错误
// Argument of type ‘number‘ is not assignable to parameter of type ‘string‘.
echoValue(1)
还需要一个 输入布尔值 => 返回布尔值 的函数
function echoValue(args: boolean): boolean {
return args
}
// ?正确
echoValue(true)
// ?错误
// Argument of type ‘number‘ is not assignable to parameter of type ‘boolean‘.
echoValue(1)
可以发现以上三个函数,只是参数类型和返回类型不一致,看起来很冗余。
我们可以使用 泛型 解决这类问题。
function echoValue<T>(args: T): T {
return args
}
// ?正确
echoValue<number>(1).toFixed(2)
// ?错误
// Property ‘length‘ does not exist on type ‘number‘.
echoValue<number>(1).length
// ?正确
echoValue<string>(‘1‘).length
// ?错误
// Property ‘toFixed‘ does not exist on type ‘string‘.
echoValue<string>(‘1‘).toFixed(2)
// ?正确
echoValue<boolean>(true)
这里用了一个 类型 T
,这个 T
是一个抽象类型,只有在调用的时候才确定它的值。
定义泛型的时候,可以一次定义多个类型参数
示例
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
// ?正确
swap([3, ‘three‘])
// ?正确
swap([‘three‘, 3])
示例:直接定义
const echoValue: <T>(args: T) => T = function<T>(args: T): T {
return args
}
// ?正确
echoValue<number>(1).toFixed(2)
// ?错误
// Property ‘length‘ does not exist on type ‘number‘.
echoValue<number>(1).length
示例:使用类型别名
type EchoValue = <T>(args: T) => T
const echoValue: EchoValue = function<T>(args: T): T {
return args
}
// ?正确
echoValue<string>(‘1‘).length
// ?错误
// Property ‘toFixed‘ does not exist on type ‘string‘.
echoValue<string>(‘1‘).toFixed(2)
使用接口
interface EchoValue {
<T>(args: T): T
}
const echoValue: EchoValue = function<T>(args: T): T {
return args
}
// ?正确
echoValue<string>(‘1‘).length
// ?错误
// Property ‘length‘ does not exist on type ‘boolean‘.
echoValue<boolean>(true).length
可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以
interface EchoValue {
<T>(args: T): T
}
interface Person {
name: string
age: number
}
const echoValue: EchoValue = function<U>(args: U): U {
return args
}
// ?正确
echoValue<Person>({name: ‘Tom‘, age: 23}).name
把泛型参数当作整个接口的一个参数,这样我们就能清楚的知道使用的具体是哪个泛型类型。
interface EchoValue<T> {
(args: T): T
}
const echoValue: EchoValue<string> = function<T>(args: T): T {
return args
}
// ?正确
echoValue(‘abc‘).length
// ?错误
// Argument of type ‘number‘ is not assignable to parameter of type ‘string‘.
echoValue(1)
我们有时在操作某值的属性时,是事先知道它具有此属性的,但是编译器不知道
function keyToValue(obj: object, key: string): any {
return obj[key]
}
const stu = {name: ‘Tom‘, age: 23}
// ?正确
// 虽然正确,但是并没有检查 ‘stu‘ 对象是否拥有 ‘name‘ 属性
keyToValue(stu, ‘name‘)
// ??不会检查‘stu‘对象是否拥有‘gender‘属性
// undefined
keyToValue(stu, ‘gender‘)
通过泛型约束实现对这个问题的检查
function keyToValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
const stu = {name: ‘Tom‘, age: 23}
// ?正确
keyToValue(stu, ‘name‘)
// ?错误
// Argument of type ‘"gender"‘ is not assignable to parameter of type ‘"name" | "age"‘.
keyToValue(stu, ‘gender‘)
K
继承索引类型 keyof T
, keyof T
相当于一个由泛型变量 T
的属性名构成的联合类型。
原文:https://www.cnblogs.com/nipeiqing/p/14668919.html