如何在打字稿的泛型类中创建类型为“T”的新对象?

Posted

技术标签:

【中文标题】如何在打字稿的泛型类中创建类型为“T”的新对象?【英文标题】:How to create a new object of type 'T' in generic class in typescript? 【发布时间】:2017-12-14 02:52:06 【问题描述】:

我有以下服务

@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);
            );
    

编译成功,但浏览器控制台出现以下错误

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)

如何创建 T 类型的对象?

【问题讨论】:

【参考方案1】:

您可以将构造函数作为类泛型而不是方法传递。

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));

【讨论】:

ERROR in Error encountered resolving symbol values statically. Could not resolve type CT (position 14:52 in the original .ts file), resolving symbol CollectionServiceng build -prod 你在尝试The generic type parameter is not supported in Angular? 但是没有泛型类型参数。不是吗? 我想是的...也许是CustomClassService?我更新了答案。【参考方案2】:

名称T 仅在编译时存在。您可以将其用于类型检查,但您不能构造 T 类型的对象,除非您有权访问构造函数。

更改factory的定义,将运行时类型构造函数作为参数:

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

现在唯一的问题是弄清楚你从哪里得到类型参数;您可能还需要将它传递给item() 方法,以便编译器知道要生成Observable&lt;T&gt; 的类型。

【讨论】:

我试图通过类构造函数传递一个类型。 constructor(protected http: Http, private type: new(item: any): T)。它很丑,但效果很好。但是当我做ng build -prod 我得到ERROR in Error encountered resolving symbol values statically. Expression form not supported (position 14:53 in the original .ts file) 谷歌搜索该错误似乎表明它是您的角度模板中的问题。 medium.com/@isaacplmann/…(第 4 节)【参考方案3】:

不需要做你正在做的事情,只需做

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

如果您想要响应的自定义类型,请执行

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

CustomResponse 是一个接口。

【讨论】:

在这种情况下,我仍然得到一个简单的 Object 而不是 T 类型的对象。.map((resp: Response)=&gt; resp.json() as T) 如果CustomResponse 是一个接口就可以,但是如果它是一个有自己的方法的类就不行。为此,您必须像 OP 一样尝试并从响应中实际创建一个真实对象。 @Duncan True,尽管我仍然觉得很难看到这样做的用例? @Duncan 我怎样才能创建一个真实的对象? @AndreyK 查看我发布的答案,您必须将实际类型作为参数传递

以上是关于如何在打字稿的泛型类中创建类型为“T”的新对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何将方法的泛型类型限制为打字稿中的对象?

C#关于反射创建泛型类

如何在运行时获取泛型的类型

当类的泛型相关时,如何在两个泛型类之间创建类似子类型的关系呢

Java中的泛型方法

Java中的泛型方法