web-dev-qa-db-ja.com

typescriptのジェネリッククラスにタイプ「T」の新しいオブジェクトを作成するにはどうすればよいですか?

私は次のサービスを持っています

@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のオブジェクトを作成するにはどうすればよいですか?

6
Andrey K

名前Tは、コンパイル時にのみ存在します。型チェックに使用できますが、コンストラクターにアクセスできない限り、型Tのオブジェクトを作成することはできません。

factoryの定義を変更して、ランタイム型コンストラクターを引数として取ります。

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

ここでの唯一の問題は、type引数を取得する場所を特定することです。コンパイラが_Observable<T>_を作成するタイプを認識できるように、おそらくそれをitem()メソッドに渡す必要もあります。

6
Duncan

あなたがしていることをする必要はありません、単にする

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

応答にカスタムタイプが必要な場合は、

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

ここで、CustomResponseはインターフェースです。

1
Chrillewoodz

メソッドではなく、ジェネリッククラスとしてコンストラクターを渡すことができます。

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