代码之家  ›  专栏  ›  技术社区  ›  John Jeng

为什么这个泛型函数的type参数不接受给定的类型?

  •  0
  • John Jeng  · 技术社区  · 7 年前

    我想在一个子类和一个生成器上指定一些数据的形状,该生成器创建具有一些泛型的类 T 。 我最初的想法是使用泛型,如下所示(简化示例),但当我调用 makeMyClass 当我回来的时候 new classRef ,它给出了以下错误:

    Type 'T' is not assignable to type 'DataInterface'

    为什么不是 T 的类型 DataInterface ?

    class MySuperClass<T> {
      constructor(public data: T) {}
    }
    
    interface DataInterface {
      name: string;
    }
    
    let initData: DataInterface = {
      name: "Alice"
    };
    
    class MyClass extends MySuperClass<DataInterface>{ 
      constructor(public data: DataInterface) {
        super(data)
      }
    }
    
    function makeMyClass<T>(classRef: typeof MySuperClass): MySuperClass<T> {
        return new classRef(initData);
    }
    
    let a = makeMyClass<DataInterface>(MyClass);
    let b = a.data
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Oscar Paz    7 年前

    您的代码中有两个问题。首先,您正在定义 makeMyClass 作为泛型,但随后调用 new classRef 使用具体变量。这意味着 T 不可能是什么,一定是那种类型 type initData

    除此之外,你还宣布 classRef 作为类的类型。最好将其定义为构造函数签名,否则您将遇到以下问题 let a = makeMyClass<>(MyClass)

    您的代码将用于以下更改:

    function makeMyClass<T>(classRef: new(initData: T) => MySuperClass<T>, initData: T): MySuperClass<T> {
        return new classRef(initData);
    }
    
    let a = makeMyClass(MyClass, initData);
    let b = a.data
    

    签名 new(initData: T) => MySuperClass<T> 表示,*一个接受T类型参数并创建T类型对象的构造函数 MySuperClass<T> 二者都 MySuperClass<DataInterface> MyClass 遵守此要求。然而,你会发现 类名 不可分配给类型为的参数 typeof MySuperClass 。此外,构造函数类型的使用将限制您可以传递给具有该确切签名的构造函数的类型。如果从创建新的派生类 MySuperClass 但它有一个带两个参数的构造函数,因此无法将其用于此函数,因为它需要一个只需要一个类型参数的构造函数 T 。这可以防止运行时错误,因此您不能使用比预期更少的参数调用构造函数。

    当然,如果希望函数是泛型的,则需要传递类型为的第二个参数 T ,以传递给类的构造函数。否则,正如我所解释的,函数不能真正是泛型的,因为它被限制为 initData