【问题标题】:How to get name of generic type T inside service in Angular如何在Angular中的服务中获取泛型类型T的名称
【发布时间】:2018-08-31 01:23:28
【问题描述】:

需要基于传递给该服务的泛型类型 T 在 Angular 5 服务中创建一些工厂方法。如何获取泛型类型“T”的名称?

@Injectable()
export class SomeService<T> {

    someModel: T;

    constructor(protected userService: UserService) {

        let user = this.userService.getLocalUser();
        let type: new () => T;

        console.log(typeof(type)) // returns "undefined"
        console.log(type instanceof MyModel) // returns "false"

        let model = new T(); // doesn't compile, T refers to a type, but used as a value

        // I also tried to initialize type, but compiler says that types are different and can't be assigned

        let type: new () => T = {}; // doesn't compile, {} is not assignable to type T 
    }
}

// This is how this service is supposed to be initialized

class SomeComponent {

    constructor(service: SomeService<MyModel>) {
        let modelName = this.service.getSomeInfoAboutInternalModel();
    }
}

【问题讨论】:

标签: angular typescript


【解决方案1】:

您不能仅基于泛型类型实例化一个类。

我的意思是,如果你想要这个:

function createInstance<T>(): T {...}

这是不可能的,因为它会转译成这样:

function createInstance() {...}

如您所见,无法以任何方式对其进行参数化。

你能得到的最接近你想要的是:

function createInstance<T>(type: new() => T): T {
    return new type();
}

那么,如果你有一个带有无参数构造函数的类:

class C1 {
   name: string;
   constructor() { name = 'my name'; }
}

您现在可以这样做了:

createInstance(C1); // returns an object <C1>{ name: 'my name' }

这可以完美运行,编译器会为您提供正确的类型信息。 我使用new() =&gt; T 作为type 的类型的原因是表明您必须传递一个不带参数的构造函数,该构造函数必须返回类型T。类本身就是这样。在这种情况下,如果您有

class C2 {
    constructor(private name: string) {}
}

你会的

createInstance(C2);

编译器会抛出错误。

但是,您可以概括 createInstance 函数,使其适用于具有任意数量参数的对象:

function createInstance2<T>(type: new (...args) => T, ...args: any[]): T 
{
    return new type(...args);
}

现在:

createInstance(C1); // returns <C1>{ name: 'my name'}
createInstance(C2, 'John'); // returns <C2>{name: 'John'}

我希望这对你有用。

【讨论】:

    【解决方案2】:

    泛型用于类型验证

    class Array<T>{
      pop:() => T;
      unshift:(v:T) => void;
    }
    
    let numbers: Array<number> = ['1212']; //error
    let strings: Array<string> = ['1','2','3']; //work
    
    
    class Product{
    
    }
    
    let products: Array<Product> = [new Product(), new Product()]; //works
    

    【讨论】:

    • 这项检查是在 Array 类之外完成的,并且是在语法级别上完成的,如何在 Array 类内进行这项检查?有可能吗?
    • 看来你不懂泛型。如果您有一些对任何输入都执行相同操作的类或方法(并且它能够执行此操作),并且您希望编译器验证输出。然后,您将拥有通用功能。 T 仅用于编译器而不是代码。它可以是一个实现一些接口或扩展一些抽象类的类。
    • 换句话说 class Test{ 这里的 T 不是实例或变量,您不能将其记录到控制台或在代码中使用,只能在输入/输出类型中使用 }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    相关资源
    最近更新 更多