介绍
很多时候我们无法准确定义一个类型,它可以是多种类型,这种情况下我们习惯用 any 来指定它的类型,代表它可以是任意类型。any 虽好用,但是它并不是那么安全的,这时候应该更多考虑泛型。
function echoValue<T>(arg: T): T {
return arg
}
T 是类型变量,它是一种特殊的变量,只用于表示类型而不是值,使用 <> 定义。
定义了类型变量之后,你在函数中任何需要指定类型的地方使用 T 都代表这一种类型,这样也能保证返回值的类型与传入参数的类型是相同的了。
定义泛型变量 T,函数参数是各元素为 T 类型的数组类型, 返回值是各元素为 T 类型的数组元素。
function echoValue<T>(arg: T[]): T[] {
console.log(arg.length)
return arg
}
T 并不是固定的,你可以写成 A、B或者其他名字,而且可以在一个函数中定义多个泛型变量,如下面这个例子:
function getArray<T,U>(arg1: T, arg2: U): [T,U]{
return [arg1, arg2]
}
我们定义了 T 和 U 两个泛型变量,第一个参数指定 T 类型,第二个参数指定 U 类型,函数返回一个元组包含类型 T 和 U。
泛型类型
我们可以定义一个泛型函数类型,泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面。
type EchoValue = <T>(arg: T) => T
let echoValue: EchoValue = function<T>(arg: T): T {
return arg
}
interface EchoValue{
<T>(arg: T): T
}
let echoValue: EchoValue = function<T>(arg: T): T {
return arg
}
let echoValue2: EchoValue = function<U>(arg: U): U {
return arg
}
泛型约束
我们有时在操作某值的属性时,是事先知道它具有此属性的,但是编译器不知道,就如上面有个例子,我们访问 arg.length 是行不通的:
function echoValue<T>(arg: T): T {
console.log(arg.length)
return arg
}
现在我们可以通过泛型约束来对泛型变量进行约束,让它至少包含 length 这一属性,具体实现如下:
interface Lengthwise{
length: number
}
function echoValue<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
echoValue(3)
echoValue({value: 3, length:10})
echoValue([1, 2, 3])
|