泛型
软件工程中,需要定义良好且一致的API,也考虑可重用性,组件不仅仅支持当前的数据类型,也应该支持未来的数据类型。
在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
示例
这里,我们使用了类型变量,它是一种特殊的变量,只用于表示类型而不是值。
我们在<>
中,添加了类型变量T,T帮助我们捕获开发者传入的类型(如 : number),我们就可以使用这个类型了。
function hello<T>(arg : T) {
return arg
}
我们定义了泛型函数后,可以使用两种方法。第一种是传入所有的参数,包括类型函数
hello<string>('hello')
另外一种是类型推断
hello('hello')
1. 使用泛型变量
可以像上面的例子一样在函数中使用泛型变量。
function hello<T>(arg : T) {
return arg
}
当我希望arg
是一个T
类型的数组时候,可以
function hello<T>(arg : T[]) :T[]{
console.log(arg.length)
return arg
}
2. 泛型类型
我们可以使用不同的泛型参数名,只要数量和使用方式对应上就可以了
function hello<T>(arg: T): T {
return arg
}
let myHello: <U>(arg: U) => U = hello
在接口一章中,我们定义了一个函数类型的接口
interface SearchFunc {
(source : string,subString : string) : boolean
}
同样的,我们可以在函数使用带有调用签名的对象字面量来定义泛型函数
interface HelloFn<U> {
(arg : U) : U
}
let myHello : HelloFn = hello
let myHello : {<U>(arg : U) : U} = hello
除了泛型接口,我们还可以创建泛型类。 注意,无法创建泛型枚举和泛型命名空间。
3. 泛型类
泛型类看上去与泛型接口写法差不多
class A<T> {
data : T
add : (x : T,y : T) => T
}
let a = new A<number>()
注意 : 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型
4. 泛型约束
我们可以使用extends
对泛型进行约束,如继承一个接口,这样就可以在函数中访问一些接口变量了
interface LengthWise {
length : number
}
function hello<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
现在这个泛型函数被定义了约束,因此它不再是适用于任意类型
hello(3) // Error
hello({length : 6}) // OK
5. 在泛型约束中使用类型参数
你可以声明一个类型参数,且它被另一个类型参数约束。
现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj 上,因此我们需要在这两个类型之间使用约束
function getProperty<T,K extends keyof T>(obj : T,key : K) {
return obj[key]
}
网友评论