五、泛型

2020-02-19  本文已影响0人  zdxhxh

泛型

软件工程中,需要定义良好且一致的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]
}
上一篇 下一篇

猜你喜欢

热点阅读