如何在打字稿的泛型类中创建类型为“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 CollectionService
当ng 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<T>
的类型。
【讨论】:
我试图通过类构造函数传递一个类型。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)=> resp.json() as T)
如果CustomResponse
是一个接口就可以,但是如果它是一个有自己的方法的类就不行。为此,您必须像 OP 一样尝试并从响应中实际创建一个真实对象。
@Duncan True,尽管我仍然觉得很难看到这样做的用例?
@Duncan 我怎样才能创建一个真实的对象?
@AndreyK 查看我发布的答案,您必须将实际类型作为参数传递以上是关于如何在打字稿的泛型类中创建类型为“T”的新对象?的主要内容,如果未能解决你的问题,请参考以下文章