2017-08-10 80 views
0

我有一個表示數據模型的抽象類。我們稱之爲模型。它實際上是在ModelData類型中進行參數化的,它表示模型實際具有的數據類型。所以:Typescript:構造函數的散列

export interface ModelData { type: string; attributes: {} } 
export class Model<D extends ModelData> {} 
export interface UserData extends ModelData 
    { type: 'users', attributes: { name: string; }} 
export class Users extends Model<UserData> {} 

問題是,我想保留模型構造函數的存儲庫。當我的數據存儲向我發送一個形如「{ type: 'users', id: 1 }」的引用列表時,我喜歡能夠執行refs.map(v => new ctors[v.type]({id: v.id}))或類似的操作。

的問題是,我不知道如何聲明說:「這個對象的字符串索引集子類構造的。

我用來做

private types: { [type: string]: typeof Model } 

然後

find<T extends ModelData>(ref: ModelReference): Model<T> { 
    return new types[ref.type]({id: ref.id}) 
} 

或多或少(爲了簡潔省略了額外的空警衛和其他代碼。

這實際上並不正確 - 我實際返回的東西是extends Model<T>,而我在類型中存儲的不是typeof Model,而是extends typeof Model

在2.4.1之前(我認爲這與隱式通用更改有關)編譯的代碼沒有抱怨,儘管不正確。我很高興與使它是正確的,但我不知道我怎麼可以實際表達這種使用打字稿。

我得到的具體東西是一組ModelData類型,它們爲ModelData的屬性和關係屬性定義了不同的形狀,以及爲每個ModelData類型擴展Model的一組類。所以,雖然技術上我可以返回一個模型,但我寧願返回一個用戶,因爲我可能會在用戶上添加一些額外的便利方法。

那麼,是不是可以說,「這個東西包含了構造函數的字符串索引組,以及所有那些建設者遵循的模式‘擴展抽象類’

回答

1

我建議做這樣的事情:

const types = { 
    'users': Users, 
    // ... other Models 
} 

function find<K extends keyof typeof types>(ref: { type: K }): typeof types[K]['prototype'] { 
    return new types[ref.type](); // this only works if all Models have no-arg constructors 
} 

如果您需要驗證types是正確的事情,存在使用new關鍵字來引用的東西構造函數的方式:

type Constructor<T> = { 
    new(...args: any[]): T; 
    readonly prototype: T; 
} 

如果我想要說「這個對象有哪些是合適的Model類型,其中關鍵是一樣的ModelData['type']值構造值」,我會說:

type ModelMap<T> = { 
    [K in keyof T]: Constructor<Model<ModelData & { type: K }>> 
} 
function verifyTypes<T>(types: T, alsoTypes: ModelMap<T>) { } 
verifyTypes(types, types); 

如果verifyTypes()給你一個編譯器錯誤,這是因爲該值是最糟糕的:

const types = { 
    'user': Users 
} 
verifyTypes(types, types); // error: type of property 'user' is incompatible 

請注意,如果您Model類型實際上守住右邊ModelData類型的某些屬性,編譯器只會生氣。如果他們是空的,因爲你的例子顯示,你的所有類型將是同樣的結構,編譯器會從不抱怨:

export class Model<D extends ModelData> { 
    data: D; // that's enough 
} 

希望有所幫助。祝你好運!

+0

嗯,這更接近我需要的東西。有沒有辦法在那裏使用類型作爲實例變量,所以我可以'find '? (沒有開箱即可使用)。這使我可以在我的數據存儲的子類中真正定義實際類型(數據存儲是通用的,子類添加具體的項目特定數據類型) – pfooti

+0

您可以嘗試'this ['types']'而不是'typeof this.types ',但我認爲''這個''多態性可能會使這件事發生。如果你的類名是'DataStore'並且它有'types'屬性,那麼你可以使用'DataStore ['types']'而不是'typeof this.types'。 – jcalz

相關問題