TS泛型技巧学习

841 阅读2分钟

一、 理解

  • 类型系统的函数
  1. 比如某一类对象,在不清楚这类对象具体有哪些key,以及key对应的类型时,方便用参数来代替,并且在真正使用的时候,传入具体的类型或key。
  2. 当准备使用 any 时,可以考虑用泛型代替
  • 对于某个函数的类型是泛型时,当调用这个函数时不用传泛型参数,会自动根据这个函数的参数类型去推断!
    • 函数泛型写法
      function identity<T>(arg: T): T {
          return arg;
      }
      interface GenericIdentityFn {
          <T>(arg: T): T;
      }
      let myIdentity: <U>(arg: U) => U = identity;
      
      let output = identity<string>("myString");
      // 或
      let output2 = identity("myString");  
    
    • 刚开始以为,既然函数可以这样反推类型,为什么对象不可以?
    • 仔细看看后,在上面的例子中,发现函数和对象的使用时机和定义的方式是不一样的。函数在定义值时就已经知道了类型,或者在定义值的时候也可以同时定义类型。但是对象没有。
    type obj<p> = {
      t:p,
      fn: (a:p) => p
    }
    const a:obj<string> = {
      t: "2",
      fn: function (c) { // 在给函数赋值时,就已经知道这个函数类型
          console.log(c)
          return c
      }
    }
    a.fn("aa")
     
     // 在定义值得时候同时定义类型
    const fc = function<p> (k: p):p {
    	return k
    }
    fc(3)
    
    // 当函数像使用对象那样定义类型,再赋值时,
    type fn<p>= (k:p)=>void;
    // 泛型也必须传参数
    const fn:fn<string> = function (k:string) {
      return k
    }
    fn("2")
    

二、泛型与js某些相同的语法

  1. 继承
  1. interface 可以使用继承 extends, type不可以使用继承
  2. 使用继承可以来表达默认值和进行一些类型的约束
  1. 默认值, 再写树形节点的类型时,对childField字段可能是 "child"、"children"...等不同的字段时,可以先用个默认字段 children 代替。在真正使用时,明确知道是那个知道时再作为参数传入
// 树形节点的类型
type anyObj<T = Record<string, unknown>> = T & {
     [k:string]:any
 }
type treeNode<a, p extends string = "children"> = {
   [k in p]:treeNode<a, p>[];
 } & anyObj<{
  active: a;
  expand?: boolean;
 }>
 
 /*  [k in p]:treeNode<a, p>[]; // 遍历 传入的参数p 的类型值,
 * 虽然它的值肯定只用一个。但是直接写 [k:p]:treeNode<a, p>[]; 会报 k的值只能为 string or number
 */
 
 // 不把 {active: a; expand?: boolean;} 和 [k in p]:treeNode<a, p>[]; 写一起是因为 写在一起会报错的,具体原因,还没理解清楚

三、功能强大,常用的关键子

  1. keyof

提出对象类型的 key 值作为联合类型

   type obj = {
       a: number;
       b: string;
   }
   type a = keyof obj ; // "a" || "b
  1. in

遍历的作用

   type arr = "a" | "b"
   type obj = {
       [k in arr]: string;
   }
   // 可以理解 keyof 和 in 功能相反互补
  1. extends:继承
  2. infer:条件类型

比较复杂一些,可看这篇文章 [TypeScript] 在条件类型中使用 infer 关键字 比较详细清楚的讲解类型的文章

  1. 你不知道的 TypeScript 高级技巧