7.泛型

78 阅读3分钟

7.泛型

  • 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

  • 泛型T作用域只限于函数内部使用

7.1 泛型函数

  • 首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值

function createArray<T>(length: number, value: T): Array<T> {

let result: T[] = [];

for (let i = 0; i < length; i++) {

result[i] = value;

}

return result;

}

let result = createArray<string>(3,'x');

console.log(result);

7.2 类数组

  • 类数组(Array-like Object)不是数组类型,比如 arguments

function sum() {

let args: IArguments = arguments;

for (let i = 0; i < args.length; i++) {

console.log(args[i]);

}

}

sum(1, 2, 3);

let root = document.getElementById('root');

let children: HTMLCollection = (root as HTMLElement).children;

children.length;

let nodeList: NodeList = (root as HTMLElement).childNodes;

nodeList.length;

7.3 泛型类

7.3.1 泛型类


class MyArray<T>{

private list:T[]=[];

add(value:T) {

this.list.push(value);

}

getMax():T {

let result=this.list[0];

for (let i=0;i<this.list.length;i++){

if (this.list[i]>result) {

result=this.list[i];

}

}

return result;

}

}

let arr=new MyArray();

arr.add(1); arr.add(2); arr.add(3);

let ret = arr.getMax();

console.log(ret);

7.3.2 泛型与 new


function factory<T>(type:{new():T}):T{

return new type();

}

class Person{}

let p:Person= factory<Person>(Person);

console.log(p);

function factory2<T>(type:{new(name:string):T},name:string):T{

return new type(name);

}

class Person2{

name:string;

constructor(name:string){

this.name=name;

}

}

let p2:Person2 = factory2<Person2>(Person2,'张三');

console.log(p);

7.5 泛型接口

  • 泛型接口可以用来约束函数

interface Calculate{

<T>(a:T,b:T):T

}

let add:Calculate = function<T>(a:T,b:T){

return a;

}

add<number>(1,2);

interface Calculate2{

<T>(a:T,b:T):T

}

let sum2: Calculate2 = function <T>(a: T, b: T): T {

return a;

};

sum2<number>(1, 2);

interface Calculate3<T>{

<U>(a:T,b:T):U

}

let sum3: Calculate3<number> = function <U>(a: number, b: number): U {

return a as any

};

let res = sum3<string>(1, 2);

7.6 多个类型参数

  • 泛型可以有多个

function swap<A,B>(tuple:[A,B]):[B,A]{

return [tuple[1],tuple[0]];

}

let swapped = swap<string,number>(['a',1]);

console.log(swapped);

console.log(swapped[0].toFixed(2));

console.log(swapped[1].length);

7.7 默认泛型类型


function createArray3<T=number>(length: number, value: T): Array<T> {

let result: T[] = [];

for (let i = 0; i < length; i++) {

result[i] = value;

}

return result;

}

let result2 = createArray3(3,'x');

console.log(result2);

7.8 泛型约束

  • 在函数中使用泛型的时候,由于预先并不知道泛型的类型,所以不能随意访问相应类型的属性或方法。

function logger<T>(val: T) {

console.log(val.length); //直接访问会报错

}

//可以让泛型继承一个接口

interface LengthWise {

length: number

}

//可以让泛型继承一个接口

function logger2<T extends LengthWise>(val: T) {

console.log(val.length)

}

logger2('zhufeng');

logger2(1);


//判断兼容不兼容跟extends继承没有一点关系 ,只看形状 有没有对应的属性

class GrandFather {

grandFather:string

}

class Father extends GrandFather {

father:string;

}

class Child extends Father{

child:string

}

//约束

//或说T能赋值给Father

//T是Father的子类型

function get<T extends Father>(){

}

let father = new Father();

let child = new Child();

father = child;

7.9 泛型接口

  • 定义接口的时候也可以指定泛型

interface Cart<T>{

list:T[]

}

let cart:Cart<{name:string,price:number}> = {

list:[{name:'zhufeng',price:10}]

}

console.log(cart.list[0].name,cart.list[0].price);

7.10 compose


type Func<T extends any[], R> = (...a: T) => R

/**

* Composes single-argument functions from right to left. The rightmost

* function can take multiple arguments as it provides the signature for the

* resulting composite function.

*

* @param funcs The functions to compose.

* @returns A function obtained by composing the argument functions from right

* to left. For example, `compose(f, g, h)` is identical to doing

* `(...args) => f(g(h(...args)))`.

*/

export default function compose(): <R>(a: R) => R

export default function compose<F extends Function>(f: F): F

/* two functions */

export default function compose<A, T extends any[], R>(

f1: (a: A) => R,

f2: Func<T, A>

): Func<T, R>

/* three functions */

export default function compose<A, B, T extends any[], R>(

f1: (b: B) => R,

f2: (a: A) => B,

f3: Func<T, A>

): Func<T, R>

/* four functions */

export default function compose<A, B, C, T extends any[], R>(

f1: (c: C) => R,

f2: (b: B) => C,

f3: (a: A) => B,

f4: Func<T, A>

): Func<T, R>

/* rest */

export default function compose<R>(

f1: (a: any) => R,

...funcs: Function[]

): (...args: any[]) => R

export default function compose<R>(...funcs: Function[]): (...args: any[]) => R

export default function compose(...funcs: Function[]) {

if (funcs.length === 0) {

// infer the argument type so it is usable in inference down the line

return <T>(arg: T) => arg

}

if (funcs.length === 1) {

return funcs[0]

}

return funcs.reduce((a, b) => (...args: any) => a(b(...args)))

}

//使用例子

const f = (arg:string) => `函数f(${arg})`

// function g

const g = (arg:string) => `函数g(${arg})`

// function h 最后一个函数可以接受多个参数

const h = (...arg:string[]) => `函数h(${arg.join('_')})`

console.log(compose(f,g,h)('a', 'b', 'c')) //函数f(函数g(函数h(a_b_c)))

console.log(compose()("zhufeng")); //zhufeng

function add1(str:string){return str+'1'}

function add2(str:string) {return str + "2";}

console.log(compose<string,any[],string>(add1, add2)("zhufeng")); //zhufeng21

7.11 泛型类型别名

  • 泛型类型别名可以表达更复杂的类型

  • Interface 和type的区别

能用interface实现的不要用type


type Cart<T> = {list:T[]} | T[];

let c1:Cart<string> = {list:['1']};

let c2:Cart<number> = [1];

7.12 泛型接口 vs 泛型类型别名

  • 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不创建新的名字,例如报错信息就不会使用别名

  • 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名

  • 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适