五. 泛型

软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

基本使用

例如我们写了一个纯函数,接收一个数字然后返回该数字

function goBack(val: number):number {
    
    
    return val
}

我们考虑到将来可能这个函数还会接收其他类型的数据,我们可能会使用any去修改

function goBack(val: any):any{
    
    
    return val
}

但我们知道,使用any其实就是关闭了ts的类型监测,而且在使用函数的时候我们也完全不知道传入跟返回的数据类型。这个时候我们就可以使用泛型来解决。

function goBack<T>(val: T):T {
    
    
    return val
}

函数上的T我们可以简单的看成一个变量,这个变量表示的一个数据类型,至于它具体表示哪种数据类型就由我们使用的时候自己决定。这样我们就定义了这个函数的入参与返回值永远是统一数据类型的值。

我们可以这样使用它

goBack<number>(1)
//甚至可以直接省略类型,让他进行自动推导
goBack(1)

多个泛型

泛型也可以同时指定多个

function goBack<T, K>(val1: T, val2: K):T {
    
    
    return val1
}
goBack<number, string>(1, '1')

泛型变量

因为泛型表示了所有类型,所以你不能对泛型表示的变量任意使用

function goBack<T>(val1: T):number {
    
    
    return val1.length
}
goBack<Array>([])

上面代码里虽然我定义了泛型为数组类型,并且传入了一个数组,但是函数并不能保证你今后每次调用都限定数组类型,所以直接在参数上面调用length方法是不行的。你可以将泛型作为数组的元素类型进行定义。

function goBack<T>(val1: Array<T>):number {
    
    
    return val1.length
}
const len = goBack<string>(['1'])
console.log(len)  //1

泛型接口

我们可以使用接口对泛型进行泛型约束

interface Len {
    
    
    length: number
}

function A <T extends Len>(val: T):number {
    
    
    return val.length
}

console.log(A({
    
    length: 1}))
console.log(A([]))
console.log(A('1'))
// console.log(A({})) 报错
// console.log(1) 报错

我们也可以直接使用接口定义泛型

interface A{
    
    
    <T>(arg: T): T;
}
function a<T>(val: T): T {
    
    
    return val
}
let myFn: A = a
console.log(myFn(1)) // 1

当然也可以手动的给接口赋值类型

interface A<T>{
    
    
    (arg: T): T;
}
function a<T>(val: T): T {
    
    
    return val
}
let myFn: A<string> = a
console.log(myFn('1')) 

泛型类

泛型类看上去与泛型接口差不多。 泛型类使用(<>)括起泛型类型,跟在类名后面。

class GenericNumber<T> {
    
    
    zeroValue?: T;
    add?: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
    
     return x + y; };

猜你喜欢

转载自blog.csdn.net/qq_44473483/article/details/134970553