//泛型
//没有使用泛型的函数
function identity(arg:number):number{
    return arg;
}

//采用类型遍历,T是类型变量,帮助捕获用户传入的类型,返回时会保留传入的类型
//同时不同于any,any会丢失部分信息。
function identity2<T>(arg:T):T {
    return arg;
}

//使用泛型函数,此处输出的类型将会是string
let output = identity2<string>('myString');
//采用类型推论,编译器会根据传入的参数自动帮助我们确定T的类型
let output2 = identity2('myString')

//使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体内必须正确的使用这个通用的类型
//此处loggingIdentity会出现 报错 T doesn‘t have 。length
function loggingIdentity<T>(arg:T):T {
    console.log(arg.length)
    return arg;
}
//此处明确指定T是数组,就不会出现错误,,因为数组中有.length属性
function loggingIdentity2<T>(arg:T[]):T[] {
    console.log(arg.length)
    return arg;
}
//此处与上面效果相同
function loggingIdentity3<T>(arg:Array<T>):Array<T> {
    console.log(arg.length)
    return arg;
}

//泛型类型
//泛型函数的类型与非泛型函数的类型没有什么不同,只是有一个类型参数在最前面,像函数声明一样
function identity3<T>(arg:T):T {
    return arg;
}

let myIdentity:<T>(agr:T)=> T=identity3;
//可以使用不同的泛型参数名,效果相同
let myIdentity2:<U>(arg:U)=> U =identity3;
//可以使用带有调用签名的对象字面量来定义泛型函数
let myIdentity3:{<T>(arg:T):T} = identity3;

//第一个泛型接口
interface GenericIdentityFn{
    <T>(arg:T):T;
}
function identitys<T>(arg:T):T {
    return arg;
}
let myIdentitys:GenericIdentityFn = identitys;
//或者
//使用GenericIdentity时,需要传入一个类型参数(此处为number)用来指定泛型类型,锁定了之后代码里使用的类型
// let myIdentitys:GenericIdentityFn<number> = identitys;