简体   繁体   English

如何在typescript中的泛型类中创建类型为'T'的新对象?

[英]How to create a new object of type 'T' in generic class in typescript?

I have the following service 我有以下服务

@Injectable()
export class CollectionService<T> {    

    constructor(protected http: Http) {}

    factory<T>(item?: any): T {
        let type: new (item?: any) => T;
        return new type(item);
    }

    item(id): Observable<T> {
        return this.http.get(`${this.baseUrl}/${id}`)
            .map((resp: Response)=> this.factory(resp.json()))
            .catch((error: any) => {
                return Observable.throw(error);
            });
    }
}

Compilation passes successfully, but i have folowing error in browser console 编译成功通过,但我在浏览器控制台中有下列错误

TypeError: type is not a constructor
at PortalVideoService.webpackJsonp.../../../../../src/app/services/collection/collection.service.ts.CollectionService.factory (http://localhost:4200/main.bundle.js:1568:16)
at http://localhost:4200/main.bundle.js:1580:64
at Array.map (native)
at MapSubscriber.project (http://localhost:4200/main.bundle.js:1580:29)
at MapSubscriber.webpackJsonp.../../../../rxjs/operator/map.js.MapSubscriber._next (http://localhost:4200/vendor.bundle.js:24034:35)
at MapSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (http://localhost:4200/vendor.bundle.js:13455:18)
at XMLHttpRequest.onLoad (http://localhost:4200/vendor.bundle.js:101703:38)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:4200/polyfills.bundle.js:2838:31)
at Object.onInvokeTask (http://localhost:4200/vendor.bundle.js:93420:37)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:4200/polyfills.bundle.js:2837:36)

How can I create an object of type T? 如何创建T类型的对象?

The name T only exists at compile time. 名称T仅在编译时存在。 You can use it for type checking but you cannot construct an object of type T unless you have access to the constructor. 您可以将它用于类型检查,但除非您有权访问构造函数,否则无法构造类型为T的对象。

Change the definition of factory to take the runtime type constructor as an argument: 更改factory的定义以将运行时类型构造函数作为参数:

factory<T>(type: {new(): T}, item?: any): T {
    return new type(item);
}

Now the only problem will be working out where you get the type argument; 现在唯一的问题是找出你得到类型参数的地方; you probably also need to pass it into the item() method so that the compiler knows what type to make the Observable<T> . 您可能还需要将它传递给item()方法,以便编译器知道Observable<T>

There is no need to do what you're doing, simply do 没有必要做你正在做的事情,只需这样做

.map((resp: Response)=> resp.json())

and if you want a custom type for the response do 如果你想要一个自定义类型的响应吗

.map((resp: Response)=> resp.json() as CustomResponse) 

where CustomResponse is an interface. 其中CustomResponse是一个接口。

You may pass the constructor as a class generic, instead of method. 您可以将构造函数作为类泛型而不是方法传递。

export class CollectionService<T, CT extends { new(item?: any): T }> {    

    constructor(protected http: Http, private type: CT) {}

    factory(item?: any): T {
        return new this.type(item);
    }

    // ...
}

class CustomClass {
    constructor(private item?: any) {
    }
 };


let cs = new CollectionService<CustomClass, { new(): CustomClass }>(http, CustomClass);
console.dir(cs.factory(123));

// UPDATE
class CustomClassService extends CollectionService<CustomClass, { new(): CustomClass }> {
    constructor(protected http: Http) {
        super(http, CustomClass);
    }
}

let ccs = new CustomClassService(http);
console.dir(ccs.factory(456));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM