一、背景
泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。Ada、Delphi、Eiffel、Java、C#、F#、Swift 和 Visual Basic .NET 称之为泛型(generics);ML、Scala 和 Haskell 称之为参数多态(parametric polymorphism);C++ 和 D称之为模板。--维基百科
泛型将程序设计中逻辑相同,类型多变的场景提取成成一种范式。
//典型场景
function outNum(arg:number): number{
return arg;
}
function outString(arg: string): string{
return arg;
}
//脚本语言解决方案
// 缺点:缺乏输入输出之间的关系和信息
function out(arg: any): any{
return arg;
}
// 引入泛型
function echoOut<T>(arg: T): T{
return arg;
}
二、泛型的使用方式
//可以明确给类型参数 T 赋值
let output = echoOut<string>("someString");
// 可以将省略类型参数 T,交由 ts 编译器来根据传入的参数自动推断
let output2 = echoOut("someString");
上述使用方式潜在问题
function echoOut<T>(arg: T): T{
//此处报错,因为 T 未明确指出其所涵盖的类型均有length 属性
console.log(arg.length);
return arg;
}
// 正确的使用方式
function echoOut<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
// 另外一种书写方式
function echoOut<T>(arg: Array<T>): Array<T>{
console.log(arg.length);
return arg
}
// 为泛型提供类型约束
interface lengthTrait{
length: number;
[propName: string]: any;
}
function echoOut<T extends lengthTrait> (arg: T): T{
console.log(arg.length);
return arg;
}
echoOut(3); // error
echoOut({length: 3, value: "dddd"}); // right
三、泛型用于接口
function echoOut<T>(arg: T): T{
return arg;
}
//一下两种写法都可以
let myEchoOut: <T>(arg: T) => T = echoOut;
let myEchoOut1: <U>(arg: U) => U = echoOut;
// 另外一种写法
let myEchoOut2: {<T>(arg: T) => T} = echoOut;
// 将{<T>(arg: T) => T} 声明一下
interface GenericEchoFn{
<T>(arg:T) => T;
}
//简写形式
let myEchoOut2: genericEchoFn = echoOut;
//继续为接口添加属性
interface GenericEchoFn{
name: T;
<T>(arg: T) => T;
}
// 简化接口书写方式
interface GenericEchoFn<T>{
name: T;
(arg: T) => T;
}
// 上述的书写方式带来一个问题
let myEchoOut3: GenericEchoFn<string> = echoOut;
四、泛型用于类
class Demo<T>{
bar: T;
constructor(bar: T){
this.bar = bar;
}
foo(x:T, y: T) => T{
return x+y;
}
}
let demo = new Demo<string>();
demo.bar = 33; // error
let strPlus = demo.foo("a","b"); //right