美文网首页
TS泛型工厂函数、泛型函数重载

TS泛型工厂函数、泛型函数重载

作者: wyc0859 | 来源:发表于2022-03-17 00:21 被阅读0次

    工厂函数类型定义:代表任意一个类的构造函数 的函数类型
    泛型工厂函数定义:一个可以创建任意类对象的通用泛型函数
    泛型工厂函数应用场景:
    使用场景1:在一些不方便或者没有办法直接 new 类名来创建对象(如装饰器)
    使用场景2:在一些项目测试或者调试中简化代码使用。

    class Son {
      public cname: string = "名字";
      public sex = "未知";
      static count: number;
    
      //鼠标放construct上会就显示:constructor Son(cname: string, sex: string): Son
      constructor(cname: string, sex: string) {
        this.cname = cname;
        this.sex = sex;
      }
      eat(): void {}
    }
    
    //Son这个类名变量,有双重性质  1.类构造函数对象变量  2.创建类对象的一个类型【new 后面出现的就是】
    type promiseFuncType = (resolve: string, reject: string) => any; // 这个是函数类型
    
    type ConstructorType = new (...arg: any) => any; //这是工厂函数类型
    // 工厂函数类型 [代表任意一个 类构造函数对象变量 的函数类型]
    // 这个new 不是创建的意思,而是表示后面的类型是一个 类构造函数对象变量的类型【类构造函数的类型】
    

    工厂函数

    //function Factory(Constructor: { new (...arg: any): any }) {
    // 上面是interface类型,下面是type类型,一个意思。记得interface需把=>改成:
    function Factory(Constructor: ConstructorType) {
      console.log(Constructor.name + "被工厂函数创建对象");
      return new Constructor("小A", "男"); //值暂时写死,后面再写工厂函数如何传参
    }
    // 使用工厂函数来new创建对象
    let obj = Factory(Son); //obj是any类型,所以不能点操作
    console.log("obj:", obj); //obj: Son { cname: '小A', sex: '男' }
    

    泛型工厂函数

    function Factory2<T>(Constructor: { new (...arg: any): T }): T {
      console.log(Constructor.name + "被泛型工厂创建对象");
      return new Constructor("小B", "男");
    }
    let obj2 = Factory2<Son>(Son); //obj2是Son类型,自然可以点操作
    console.log("obj2:", obj2);
    

    交叉类型

    //定义:将多个类型合并【多个类型属性和方法的并集】成的类型就是交叉类型。
    type objtype1 = { username: string, age: number }
    type objtype2 = { custname: string, phone: number, age: number }
    type objtype3 = { address: string }
    
    let first: objtype1 = { username: "wangwu", age: 23 }
    let second: objtype2 = { custname: "lisi", phone: 111, age: 23 }
    
    // 定义:将多个类型合并【多个类型属性和方法的并集】成的类型就是交叉类型。
    let jiaochatype: objtype1 & objtype2 & objtype3 = {
      username: "wangwu", age: 23, custname: "lisi", phone: 111, address: "shanghai"
    }
    
    let uniontype: objtype1 | objtype2 = {
      username: "wangwu", age: 23, custname: "lisi", phone: 111
    }
    

    泛型函数重载+ 交叉类型+ 类型断言

    interface Button {
      btntype: string;
      text: string;
    }
    interface Link {
      alt: string;
      href: string;
    }
    interface Href {
      linktype: string;
      target: Openlocation;
    }
    enum Openlocation {
      self = 0,
      _blank,
      parent,
    }
    let button: Button = {
      btntype: "normal",
      text: "跳转",
    };
    let link: Link = {
      alt: "goto",
      href: "xx.com",
    };
    let href: Href = {
      linktype: "xx网",
      target: Openlocation._blank,
    };
    
    type union<T = any> = Extract<T, object>;
    function cross<T, U>(objOne: union<T>, objTwo: union<U>): T & U;
    function cross<T, U>(objOne: union<T>, objTwo: union<U>): T & U;
    function cross<T, U, V>(
      objOne: union<T>,
      objTwo: union<U>,
      objThree: union<V>
    ): T & U & V;
    function cross<T, U, V>(
      objOne: union<T>,
      objTwo: union<U>,
      objThree?: union<V>
    ) {
      let obj = {};
      let combine = obj as T & U;
    
      Object.keys(objOne).forEach((key) => {
        combine[key] = objOne[key];
      });
      Object.keys(objTwo).forEach((key) => {
        if (!combine.hasOwnProperty(key)) {
          combine[key] = objTwo[key];
        }
      });
      if (objThree) {
        //如果有第三个对象传递进来实现交叉
        //let obj = {}
        //let combine2 = obj as T & U & V
        //let combine2=combine as T & U & V
        let combine2 = combine as typeof combine & V;
        Object.keys(objThree).forEach((key) => {
          if (!combine2.hasOwnProperty(key)) {
            combine2[key] = objThree[key];
          }
        });
        return combine2; // 三个对象交叉结果
      }
      return combine; // 两个对象交叉结果
    }
    let combine = cross(button, link);
    console.log(combine);
    let combine2 = cross(button, link, href);
    console.log(combine2);
    export {};
    

    泛型工厂函数+传参

    class TestClass {
      // 准备类
      public name: string;
      public classno: number;
      constructor(name: string, classno: number) {
        this.name = name;
        this.classno = classno;
      }
      eat() {
        console.log("姓名为: " + this.name + ",班级:" + this.classno);
      }
    }
    
    //TestClass这个类名变量,有双重性质  1.类构造函数对象变量  2.创建类对象的一个类型【new 后面出现的就是】
    //new TestClass(); //这个实例化,TestClass类名不是构造函数的代名词,而是一个类型
    //type Constructor<T> = new (...args: any[]) => T; //这个函数类型,有new是构造函数类型
    
    //想获取TestClass类中构造函数的参数及类型,方法如下:
    type CstParams<T> = T extends new (...args: infer P) => any ? P : never;
    
    type funType = new (name: string, classno: number) => any;
    let test: CstParams<funType>; //test: [name: string, classno: number]
    
    type funType1 = typeof TestClass;
    let test1: CstParams<funType1>; //test1: [name: string, classno: number]
    //上面2个例子结果都是一样,得到元组,说明testClass是类构造函数代名词
    

    上面的方式加上泛型约束

    type TypCstParams2<T extends new (...args: any[]) => any> = T extends new (
      ...args: infer P
    ) => any
      ? P
      : never;
    
    type TypConstructor<T> = new (...args: any[]) => T; //通用泛型构造函数约束
    
    //------------------------------------------------------
    //这句不能提出来:CP extends new (...args: any[]) => any
    function createInstance<T, CP extends new (...args: any[]) => any>(
      constructor: TypConstructor<T>,
      ...args: TypCstParams2<CP>
    ) {
      return new constructor(...args);
    }
    createInstance<TestClass, typeof TestClass>(TestClass, "wangwu", 105).eat();
    

    相关文章

      网友评论

          本文标题:TS泛型工厂函数、泛型函数重载

          本文链接:https://www.haomeiwen.com/subject/qfjpdrtx.html