typescript入门(五)泛型

375 阅读2分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。

一、泛型的作用

泛型的作用:

  • 使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。
  • 不必多条函数重载,冗长的联合类型声明,增强代码可读性。
  • 灵活控制类型之间的约束。

例如,要求一个方法的返回值的类型与传入参数的类型是相同的,可以使用泛型来定义。

例子:

function print1<T>(params:T):T {
    return params;
}
print1<string>('name');

上例中定义了泛型print1,用类型变量T捕获用户传入的类型string,泛型print1中使用到的类型变量T就可以看做是string。不用预先定义类型就可以保持输入参数和返回值类型一致。

二、泛型函数

上例中,我们定义了一个泛型函数,其调用方法除了上面的传入类型参数string外,还有另一种写法说直接不传类型参数,编译器会自动确定类型(类型推论)。

print1('name');

三、泛型函数类型

泛型除了可以定义函数,还可以定义函数类型。

type Print = <T>(value:T) => T;
let myPrint: Print = print1; 

上例中用type关键字定义函数类型Print,定义myPrint函数为Print类型。

四、泛型接口

泛型还可定义接口:

interface Log<T> {
    (value: T):T
}
let myLog:Log<string> = print1;
myLog('aaa')

上例中定义了函数类型的泛型接口Log,指定类型参数为T,设置接口Log中接收参数和返回值都为T类型。

可为类型参数T设置默认值:

interface Log<T=string> {
    (value: T):T
}

当有默认值时,使用泛型时就可以不传入类型:

let myLog:Log = print1;
myLog('aaa')

五、泛型类

泛型类与泛型接口差不多。类名后加参数类型。

class Log<T> {
    run(value:T):T {
        return value;
    }
}

上例中创建了泛型类Log,类中定义run方法的参数和返回值都为T类型。

类使用时可设置类型,也可不设置类型,不设置类型时可随意传值:

let log1 = new Log<number>();
log1.run(1);

let log2 = new Log();
log2.run('sss');

六、泛型约束

泛型约束既是对类型变量T的类型约束。

举个例子:

function getLength<T> (arg: T) {
    console.log(arg.length);//报错
    return arg
}

getLength<string>('22')

上例中,我们要打印参数的length属性,但是参数不一定有length属性,此时我们就需要对传入的参数联系进行约束,否则会报错。

那如何对参数进行约束呢?

类型变量T可以继承一个接口进行泛型约束,如下所示:

interface Length {
    length:number;
}

function getLength<T extends Length> (arg: T) {
    console.log(arg.length)
    return arg
}

getLength<string>('22')
getLength('33')

上例中,类型变量T继承Length接口进行泛型约束,因此传入的参数必须拥有length属性才不会报错。