2017-09-14 5 views
1

と互換性がありません:活字体:polymorhpicこの、過負荷署名は、これが動作しない理由を誰かが説明でき関数の実装

できるようになる
abstract class Model { 
    static deserialize<T extends Model>(this: (new() => T), object: any): T; 
    static deserialize<T extends Model>(ctor: (new() => T), object: any): T { 
     return new ctor(); 
    } 

    static deserializeArray<T extends Model>(this: (new() => T), ...objects: any[]): T[]; 
    static deserializeArray<T extends Model>(ctor: (new() => T), ...objects: any[]): T[] { 
     return objects.map(object => Model.deserialize(ctor, object)); 
    } 
} 

class MyModel extends Model { } 

let myModel = MyModel.deserialize({}); 
let myModels = MyModel.deserializeArray({}, {}, {}); 

または

let myModel = Model.deserialize(MyModel, {}); 
let myModels = Model.deserializeArray(MyModel, {}, {}, {}); 

Typescript 2.5.2では、「オーバーロードシグネチャは関数の実装と互換性がありません」という文句があります。

なぜ両方のフォームが必要ですか?

シリアル化された(JSON)のモデルを返しREST APIを考えてみましょう:モデルを要求する

class MyModelController { 
    get(id: number) { 
     let myModel = ... some db/service call ... 
     return myModel.serialize(); 
    } 
} 

そして汎用サービス(角度)を:

@Injectable() 
abstract class HttpService { 
    constructor(private http: Http) { } 

    errorHandler(response) { 
     ... 
    } 

    get<T extends Model>(ModelType: (new() => T), endpoint: string): Observable<T> { 
     return this.http.get(endpoint) 
      // we can't call ModelType.deserialize() here... 
      .map(response => Model.deserialize(ModelType, response.json())) 
      .catch(response => this.errorHandler(response)); 
    } 
} 

@Injectable() 
class MyModelService extends HttpService { 
    get(id: number) { 
     return super.get(MyModel, `/api/models/${id}`); 
    } 
} 

ソリューション

abstract class Model { 
    static deserialize<T extends Model>(this: (new() => T), object: {}): T; 
    static deserialize<T extends Model>(this: Function & { prototype: Model }, ctor: (new() => T), object: {}); 
    static deserialize<T extends Model>(this: (new() => T), first: (new() => T) | {}, second?: any) { 
     return typeof first === "function" ? new first() : new this(); 
    } 

    static deserializeArray<T extends Model>(this: (new() => T), ...objects: {}[]): T[]; 
    static deserializeArray<T extends Model>(this: Function & { prototype: Model }, ctor: (new() => T), ...objects: {}[]): T[]; 
    static deserializeArray<T extends Model>(this: (new() => T), first: (new() => T) | {}[], second?: {}[]): T[] { 
     const ctor = typeof first === "function" ? first : this; 
     const objects = typeof first === "function" ? second : first; 
     return objects.map(object => Model.deserialize(ctor, object)); 
    } 
} 

これにより、どちらも、abstractを保存しています。私の意見で

+0

第2フォームのポイントは何ですか?あなたが 'MyModel.deserialize({});を行うことができれば、なぜ' Model.deserialize(MyModel、{}); 'を実行する必要がありますか? –

+0

ええ、もしあなたが 'ModelType'を持っていれば' ModelType。デシリアライズ(...) '。 'Model'を確実に拡張するため、静的' deserialize'関数への参照があります。 –

+0

'ModelType.deserialize()'を呼び出すことができません。あなたが 'ModelCtor '型(逆シリアル化署名を持つ)型を含むようにリファクタリングすると、 'MyModel'は' ModelCtor 'に割り当てられません。ありがとう、これは間違いなく正しい方向に私を指摘した。 –

答えて

0

は、両方を持っている必要はありません。

let myModel1 = MyModel.deserialize({}); 
let myModel2 = Model.deserialize(MyModel, {}); 

最初の形式は、十分に、より読みやすいし、その後のコードは次のようになります。

type ModelCtor<T extends Model> = { 
    new(): T; 
    deserialize<T extends Model>(object: any): T; 
    deserializeArray<T extends Model>(...objects: any[]): T[]; 
}; 

abstract class Model { 
    static deserialize<T extends Model>(this: ModelCtor<T>, object: any): T { 
     return new this(); 
    } 

    static deserializeArray<T extends Model>(this: ModelCtor<T>, ...objects: any[]): T[] { 
     return objects.map(object => this.deserialize(object)); 
    } 
} 

class MyModel extends Model { } 

let myModel = MyModel.deserialize({}); 
let myModels = MyModel.deserializeArray({}, {}, {}); 

code in playground

しかし、何らかの理由でそれが私を超えている場合は、両方のフォームを使用したい場合は、次のようにすることができます。

type ModelCtor<T extends Model> = { 
    new(): T; 
    deserialize<T extends Model>(object: any): T; 
    deserialize<T extends Model>(ctor: ModelCtor<T>, object: any): T; 

    deserializeArray<T extends Model>(...objects: any[]): T[]; 
    deserializeArray<T extends Model>(ctor: ModelCtor<T>, ...objects: any[]): T[]; 
}; 

class Model { 
    static deserialize<T extends Model>(this: ModelCtor<T>, object: any): T; 
    static deserialize<T extends Model, S extends Model>(this: ModelCtor<T>, ctor: ModelCtor<S>, object: any): S; 
    static deserialize<T extends Model, S extends Model>(this: ModelCtor<T>, first: ModelCtor<S> | any, second?: any): S { 
     return second === undefined ? new this() : new first(); 
    } 

    static deserializeArray<T extends Model>(this: ModelCtor<T>, ...objects: any[]): T[]; 
    static deserializeArray<T extends Model, S extends Model>(this: ModelCtor<T>, ctor: ModelCtor<S>, ...objects: any[]): S[]; 
    static deserializeArray<T extends Model, S extends Model>(this: ModelCtor<T>, ...objects: any[]): S[] { 
     const ctor: ModelCtor<S> = typeof objects[0] === "function" ? objects[0] : this as any; 
     return objects.map(object => ctor.deserialize(ctor, object)); 
    } 
} 

class MyModel extends Model { } 

let myModel1 = MyModel.deserialize({}); 
let myModels1 = MyModel.deserializeArray({}, {}, {}); 

let myModel2 = Model.deserialize(MyModel, {}); 
let myModels2 = Model.deserializeArray(MyModel, {}, {}, {}); 

code in playground

コードがよりcompilatedである(と私は正当な理由なくと思います)。
はまた、私はそれ以外の場合はこのエラーがあります、Modelからabstract一部を除去しなければならなかった:これらの行の両方について

The 'this' context of type 'typeof Model' is not assignable to method's 'this' of type 'ModelCtor'.
Cannot assign an abstract constructor type to a non-abstract constructor type.

let myModel2 = Model.deserialize(MyModel, {}); 
let myModels2 = Model.deserializeArray(MyModel, {}, {}, {}); 

たぶん、あなたはもう少しそれで遊んで修正することができますabstractを削除せずにエラーが発生しました。

+0

私は質問を「抽象」を保存する解決策を含めるように更新しました。 –

関連する問題