我是 Typescript 的新手,并試圖圍繞處理基類具有一些不同屬性的類繼承的最佳方法。
基本上,我有一個基類,我想為其定義一些通用功能和一組具有不同屬性的子類,因為它們代表不同的資料庫模型。我試圖弄清楚如何讓這些型別作業。
例如:
class BaseClass {
static create(props) { /*... */ }
update(props) { /*... */ }
}
type SubClassOneProps = {
firstName: string
lastName: string
}
class SubClassOne extends BaseClass {
firstName!: string
lastName!: string
}
type SubClassTwoProps = {
streetName: string
streetNumber: number
}
class SubClassTwo extends BaseClass {
streetName!: string
streetNumber!: number
}
// I'm looking for typing that will allow me to do the following:
SubClassOne.create({firstName: "Bob", lastName: "Doe"})
SubClassTwo.create({streetName: "Sunset Blvd", streetNumber: 100})
//and then same idea with the instance methods, although I would use Partial<> with these
由于每個子類的屬性都不同,因此簽名會有所不同,即使它們都是基本的鍵/值對。我看不到如何正確輸入,也無法弄清楚如何從子類中指定屬性。
我還需要在這些屬性中的每一個上存盤一些元資料(特別是,它們是否應該可以公開訪問),然后有一個實體方法可以將公共屬性匯出到 JSON 物件。但我會把它作為另一個問題留到以后。
任何指導表示贊賞!
uj5u.com熱心網友回復:
這里的主要絆腳石是靜態類成員上缺乏多型this型別。有關詳細資訊,請參閱microsoft/TypeScript#5863。
例如成員,您可以使用命名的型別this來參考“當前”子類:
class BaseClass {
declare test: Array<this>;
}
class SubClassOne extends BaseClass { /* snip */ }
const sc1 = new SubClassOne();
sc1.test // SubClassOne[]
class SubClassTwo extends BaseClass { /* snip */ }
const sc2 = new SubClassTwo();
sc2.test // SubClassTwo[]
但是目前還沒有靜態成員的類比。對于靜態方法,您可以使用使方法泛型并通過引數this將方法的背景關系系結到泛型型別引數的解決方法:this
class BaseClass {
declare static test: <T extends BaseClass>(this: new () => T) => Array<T>;
}
class SubClassOne extends BaseClass { /* snip */ }
const sc1t = SubClassOne.test();
// const sc1t: SubClassOne[]
class SubClassTwo extends BaseClass { /* snip */ }
const sc2t = SubClassTwo.test();
// const sc1t: SubClassTwo[]
在上面,我們說test()必須在 type 的可構造物件上呼叫new () => T。當您呼叫SubClassOne.test()時,編譯器會嘗試T從typeof SubClassOne型別推斷new () => T,因此T推斷為實體型別SubClassOne。這是從建構式獲取型別的一種迂回方式this,但您可以做到。
所以現在我們必須決定如何將每個子類與其“道具”型別相關聯,因為顯然我們需要這樣做。我建議將基類設為泛型類,其中型別引數T對應于 props 型別:
class BaseClass<T extends object> {
update(props: T) { Object.assign(this, props) }
}
class SubClassOne extends BaseClass<SubClassOneProps> {
firstName!: string
lastName!: string
}
const sc1 = new SubClassOne();
sc1.update({ firstName: "Bob", lastName: "Doe" });
class SubClassTwo extends BaseClass<SubClassTwoProps> {
streetName!: string
streetNumber!: number
}
const sc2 = new SubClassTwo();
sc2.update({ streetName: "Sunset Blvd", streetNumber: 100 });
現在我們終于可以宣告了create():
class BaseClass<T extends object> {
static create<T extends BaseClass<any>>(
this: { new(): T },
props: T extends BaseClass<infer U> ? U : never
) { const ret = new this(); ret.update(props); return ret; }
}
所以thiscontextcreate()必須是一個零引數的建構式,產生一個 generic 的實體T,我們使用條件型別推斷來推斷 props 的型別。也就是說,如果T是BaseClass<X>對于某些X,則T extends BaseClass<infer U> ? U : never評估為X。
讓我們測驗一下:
const sc1 = SubClassOne.create({ firstName: "Bob", lastName: "Doe" });
// sc1: SubClassOne
console.log(sc1.firstName.toUpperCase()) // "BOB"
const sc2 = SubClassTwo.create({ streetName: "Sunset Blvd", streetNumber: 100 });
// sc2: SubClassTwo
console.log(sc2.streetNumber.toFixed(2)) // "100.00"
看起來不錯!
Playground 代碼鏈接
uj5u.com熱心網友回復:
我不相信靜態函式有比將泛型傳遞給它更干凈的方法,例如
class BaseClass {
static create<T>(props: T) {
/*... */
}
update(props) {
/*... */
}
}
type SubClassOneProps = {
firstName: string;
lastName: string;
};
class SubClassOne extends BaseClass {
firstName!: string;
lastName!: string;
}
type SubClassTwoProps = {
streetName: string;
streetNumber: number;
};
class SubClassTwo extends BaseClass {
streetName!: string;
streetNumber!: number;
}
SubClassOne.create<SubClassOneProps>({ firstName: 'Bob', lastName: 'Doe' });
SubClassTwo.create<SubClassTwoProps>({ streetName: 'Sunset Blvd', streetNumber: 100 });
在這種情況下, T 是一個泛型,它被用作道具的型別。
當我們呼叫 SubClassSmth.create({}) 時,我們傳入泛型。
如果函式不是靜態的,它可以以一種更簡潔的方式完成,例如假設 create 不是靜態的,我們可以在類級別傳入泛型,并且您不必再次撰寫它。
class BaseClass<U> {
create(props: U) {
/*... */
}
update(props) {
/*... */
}
}
type SubClassOneProps = {
firstName: string;
lastName: string;
};
class SubClassOne extends BaseClass<SubClassOneProps> {
firstName!: string;
lastName!: string;
}
type SubClassTwoProps = {
streetName: string;
streetNumber: number;
};
class SubClassTwo extends BaseClass<SubClassTwoProps> {
streetName!: string;
streetNumber!: number;
}
const subClassOneFactory = new SubClassOne();
const subClassTwoFactory = new SubClassTwo();
subClassOneFactory.create({ firstName: 'Bob', lastName: 'Doe' });
subClassTwoFactory.create({ streetName: 'Sunset Blvd', streetNumber: 100 });
關于為什么我們不能在靜態函式上使用類級泛型的附加資訊 - Calling a static function on a generic class in TypeScript
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/525732.html
標籤:打字稿班级遗产
下一篇:在某些條件下迭代兩個向量最多十次
