typescript泛型 - 个人理解

{
  class Lee {
    name: string
    age: number
    weight: number
    say() {
      console.log(this.name + '--------' + this.age + '----' + this.weight)
    }
  }

  let l = new Lee()
  l.name = 'dxw'
  l.age = 24
  l.say() // dxw--------24----undefined

  // --------------

  class Lee1<IProps> {
    user: IProps
    say() {
      console.log(this.user)
    }
  }
  interface IUser {
    name: string
    age: number
  }
  let lee = new Lee1<IUser>()
  lee.user = { name: 'dxw', age: 24 }
  lee.say() // { name: 'dxw', age: 24 }

  /**
     *  
        class Lee1<IProps> {
            user: IProps
            say() {
                console.log(this.user);
            }
        }


        // 泛型只关注于我需要的数据,不关注具体的数据格式
        interface IUser {
            name: string
            age: number
            wight: number // 新增一个属性
        }

        let lee = new Lee1<IUser>()
        lee.user = { name: 'dxw', age: 24, weight: 24} // 这里没写weight会提示赋值错误
        lee.say() // { name: 'dxw', age: 24, weight: 24 }

     */
}
{
  // 泛型例子
  function ident(arg: number): number {
    return arg // 传入number返回number
  }
  //或者使用any
  function idents(arg: any): any {
    return arg
  }
  /**
   * 传入any会导致这个函数可以接收任意参数
   * 这样就丢失了一些信息
   * 传入的类型与返回的类型应该是相同的
   * 如果传入一个数字,我们只知道任何类型的值都会有可能返回
   */

  /**
   * 我们传入类型变量T,T帮我们获取传入的类型,假如是number
   * 之后再以这个变量T返回
   * 这样就知道传入的参数类型和返回值类型是一致的了
   * 此版本的函数叫做泛型
   * 【适用于不同的类型】
   */
  function identity<T>(arg: T): T {
    return arg
  }
  console.log(identity('555'))
  console.log(identity(555))
  console.log(
    identity({
      name: 'dxw',
      age: 13
    })
  )
  // 函数泛型的使用方法(2种)
  // 1:传入所有参数,包含类型参数
  let o1 = identity<string>('ssstr')
  let o2 = identity<boolean>(false)
  // 2:利用类型推论,自动确定类型
  let o3 = identity(555)
  let o4 = identity(false)

  // 使用泛型变量
  function loggingIdentity<T>(arg: T): T {
    // console.log(arg.length);  // Error: T doesn't have .length
    return arg
  }
  /**
   * 现在没有地方声明参数arg有length的属性
   * 因为T这个变量代表的是任意类型(传入的参数类型可能是数字number,而number没有length属性,所以...)
   *
   * 想要正确的打印arg的length属性,要为其证明类型
   * 假如是数组类型,这样定义↓
   */
  function loggingIdent<T>(arg: T[]): T[] {
    // 个人理解:定义[类型参数/类型变量]T,设置T为数组类型,返回数组T
    return arg
  }
  // 数组另一种形式
  function loggingIdents<T>(arg: Array<T>): Array<T> {
    return arg
  }
}
{
  // 泛型类型

  function identant<T>(arg: T): T {
    return arg
  }
  // 类型参数在最前面 像函数声明
  let myIdentant: <T>(arg: T) => T = identant
  // let myIdentant: <U>(arg: U) => U = identant  // 数量和使用方式一样就可以
  // let myIdentant: { <U>(arg: U): U } = identant // 对象字面量

  /**
     * console.log(identant);
     * console.log(myIdentant);
     * 打印是一样的
        ƒ identant(arg) {
            return arg;
        }
     */

  // 引导去使用第一个【泛型接口】
  interface GenerIdentants {
    <T>(arg: T): T
  }
  function identants<T>(arg: T): T {
    return arg
  }
  let myIdentants: GenerIdentants = identants
  console.log(myIdentants(666), '6666')

  /**
   * 把具体类型提取出来
   * 更清楚的知道使用的是哪个泛型类型
   * (GenerIdentants<number>而不是GenerIdentants)
   */
  interface GenerIdentantsa<T> {
    (arg: T): T
  }
  function identantsa<T>(arg: T): T {
    return arg
  }
  let myIdentantsa: GenerIdentantsa<number> = identantsa
  console.log(myIdentantsa(1010), '1010')
}
{
  // 泛型类:和泛型接口类似,不限制number,还可以是其他类型
  // 注意:无法创建泛型枚举和泛型命名空间
  class Proper<T> {
    age: T
    add: (x: T, y: T) => T
  }
  let myProper = new Proper<number>()
  myProper.age = 23
  myProper.add = function (x, y) {
    return x + y
  }
}
{
  // 泛型约束
  function getLen<T>(arg: T): T {
    // console.log(arg.length) // err: 类型“T”上不存在属性“length”。
    return arg
  }

  // 限制传入的类型有这个属性就通过
  interface Lenwise {
    length: number
  }
  function logLen<T extends Lenwise>(arg: T): T {
    console.log(arg.length, 'Lenwise')
    return arg
  }
  // console.log(logLen(3)); // 类型“number”的参数不能赋给类型“Lenwise”的参数。
  logLen({ length: 5 })
  logLen([1, 2, 3])

  /**
   * 泛型约束中使用类型参数
   * 官方例子走不通 暂缓?????
   */

  // function getKey(obj: T, key: K) {
  //     return obj[key]
  // }
  // let x1 = { a: 'x', b: 5, c: false }
  // console.log(getKey(x1, 'a'));
  // console.log(getKey(x1, 'd'));
}