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,这时我们应该尽量使用接口代替类型别名
-
当我们需要使用联合类型或者元组类型的时候,类型别名会更合适