2017-12-29 9 views
3

Ich arbeite an einer generischen Typescript-Schnittstelle, wo eine Factory-Klasse mit einer bestimmten Klasse instanziiert ist und Methoden zum Erstellen verschiedener Instanzen dieser Klasse. Meine ideale Art Schnittstelle, die ich nicht zu erreichen scheinen, ist wie folgt:Typescript konvertieren Typ `Typof Foo` zu` Foo`

class BaseModel { /* impl */ } 
class Foo extends BaseModel { /* impl */ } 
class Factory<T extends BaseModel> { /* impl */ } 

let factory : Factory<Foo> = new Factory(Foo) 
let fooInstance = factory.build() // returns type: `Foo` 

aber ich kann nicht herausfinden, wie man eine Erklärung von Factory<T> zu bekommen, dies zu erreichen, ohne entweder den Rückgabetyp zu beeinträchtigen oder eine parallele Konstruktortyp Aufrechterhaltung Definition.

Wenn ich auf nichts verlassen, sondern die Art von den Klassen I erklärt habe, ist der Rückgabetyp der Build-Funktion immer BaseClass plus Ich muß die generischen Factory<typeof Foo> statt Factory<Foo> machen:

class BaseModel { 
    static classMethod() : string { 
    return 'i am class method' 
    } 

    hello() { 
    return 'hello world' 
    } 
} 
class Foo extends BaseModel {} 

class Factory<T extends typeof BaseModel> { 
    private _modelClass : T 

    constructor(modelClass : T) { 
    this._modelClass = modelClass 
    } 

    build() { 
    return new this._modelClass() 
    } 

    echoClassMethod() { 
    console.log(this._modelClass.classMethod()) 
    } 
} 

let factory : Factory<typeof Foo> = new Factory(Foo) 
let fooInstance = factory.build() // Returns type `BaseClass` instead of `Foo` 

aber wenn ich die Fabrik Interface will richtig arbeiten, ich habe eine parallel Typdefinition zu erhalten, die typeof BaseModel, sondern als Konstruktorfunktion Spiegel statt:

class BaseModel { 
    static classMethod() : string { 
    return 'i am class method' 
    } 

    hello() { 
    return 'hello world' 
    } 
} 
class Foo extends BaseModel {} 

// Have to maintain a separate type that 
// mirrors the class interface of my target class 
type BaseModelConstructor<T extends BaseModel> = { 
    new(...args: any[]) : T 
    classMethod() : string 
} 

class Factory<T extends BaseModel> { 
    private _modelClass : BaseModelConstructor<T> 

    constructor(modelClass : BaseModelConstructor<T>) { 
    this._modelClass = modelClass 
    } 

    build() { 
    return new this._modelClass() 
    } 

    echoClassMethod() { 
    console.log(this._modelClass.classMethod()) 
    } 
} 

let factory : Factory<Foo> = new Factory(Foo) 
let fooInstance = factory.build() // Correctly returns type `Foo` 

Es muss einen besseren Weg geben, einen typeof X in einen X umzuwandeln oder umgekehrt?

Antwort

3

Um typeof X-X, können Sie in der Regel lookup die prototype Eigenschaft des typeof X Konstruktortyp zu bekommen. Zum Beispiel in der folgenden habe ich die Rückgabetyp build() kommentierte T['prototype'] sein:

class Factory<T extends typeof BaseModel> { 
    private _modelClass : T 

    constructor(modelClass : T) { 
    this._modelClass = modelClass 
    } 

    // note the declared return type 
    build(): T['prototype'] { 
    return new this._modelClass() 
    } 

    echoClassMethod() { 
    console.log(this._modelClass.classMethod()) 
    } 
} 

Und dann die folgenden Werke:

let factory = new Factory(Foo) 
let fooInstance = factory.build() // Foo, as desired. 

Does diese Hilfe? Viel Glück!

+0

Dies ist sehr hilfreich und kümmert sich perfekt um meine Probleme. Für Typ Einfachheit habe ich eine zweite generische mit einem Standard hinzugefügt: 'Klasse Factory ' War vorher nicht bewusst Sie Referenz Typen von Mitgliedern in diesen Weg. Sollte helfen, etwas von meinem anderen Typisierungscode zu säubern. –

Verwandte Themen