概念:泛型允许在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。
理念灌输
函数、接口或类将处理多种数据类型,并在在多个地方使用该数据类型时。
函数、接口或类要限制参数是多种数据类型但是要包含某个属性时就要泛型约束
1.泛型函数(官网叫的,其实也就是在函数中使用泛型)
function identity<T>(arg: T): T { return arg; }
let output = identity<string>("myString");//type of output will be 'string'
我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。
function loggingIdentity<T>(arg: T[]): T[] { console.log(arg.length);
// Array has a .length, so no more error return arg; }
你可以这样理解loggingIdentity的类型:泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型是T的数组。 如果我们传入数字数组,将返回一个数字数组,因为此时 T的的类型为number。 这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性。
2.泛型接口
比如:组件有个参数是函数 但是这函数要符合我们的规定
interface GenericIdentityFn { <T>(arg: T): T; }
function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn = identity;
比如:
interface Mes<T, M> { time: T, message: M }
function mesFn<T, U> (time: T, message: U): Mes<T, U> {
console.log(time+ ": " + typeof (time));
console.log(message + ": " + typeof (message));
let mes: Mes<T, U> = { time, message }; return mes;
}
3. 泛型类
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。
注意:类的静态属性不能使用这个泛型类型。
class AddC<T> {
value: T;
add: (x: T, y: T) => T;
}
let myNum = new AddC<number>();
myNum.value = 0;
myNum.add = function(x, y) { return x + y; };
4.泛型约束
// 需要限制传入的参数都有 name 属性的数组我们可以这么写
function getNameList<T extends { name: string }>(items: T[]):string[] {
return items.map(i=> i.name)
}
结合keyof和extends 操作符,我们就可以获取指定类型的所有键,我们限制输入的属性名包含在 keyof 返回的联合类型中。具体的使用方式如下
enum level{ Easy, Intermediate, Hard }
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let info = { name: "Typescript", difficulty: level.Intermediate }
let difficulty: level= getProperty(info, 'difficulty');
// let supersetOf: string = getProperty(info, 'abc'); // 报错
5 条件类型用到泛型
type P<T> = T extends 'x' ? string : number; type A = P<'x' | 'y'>
// A的类型是 string | number