如果我有類似的東西
class A{
_arr: /* dont know what to write here*/ = []
addEl<T>(el: T): {
this._arr.push(el)
}
}
我想像這樣使用它
const instance = new A();
instance.addEl<"whatever">("whatever");
// type of instance._arr should be ["whatever"]
instance.addEl<number>(42)
// type of instance._arr should be ["whatever", number]
那可能嗎?對于 _arr 的型別,我需要做什么?
uj5u.com熱心網友回復:
如被問及,這是不可能的。TypeScript 的型別系統不會對值型別的任意突變進行建模。如果變數被注釋為 type 0,那么以后就不能將其更改為 type 的值1。編譯器確實通過控制流分析執行縮小范圍,從而可以根據某些檢查或操作看到變數的型別變得更具體,這確實使編譯器具有一些跟蹤變數狀態變化的小能力......但它是相當有限。如果您知道每次呼叫instance.addEl()都只會縮小 的型別instance,那么您可以嘗試創建addEl()一個斷言方法,但這些都很脆弱且難以使用。這對您來說甚至都不可用,因為元組型別具有已知length屬性,并且呼叫addEl()會有效地instance._arr.length從 type0的值更改為 type的值1,這是編譯器不允許的:
const instance = new A();
instance._arr // should be []
instance._arr.length // should be 0
instance.addEl<"whatever">("whatever");
instance._arr // should be ["whatever"]
instance._arr.length // should be 1, but this is impossible
與其嘗試重構代碼以使用控制流分析,我的建議是擁抱 TypeScript 的強大型別系統并忘記變異狀態。因此,而不是具有單一實體,其狀態在每次呼叫后改變了addEl(),你有不變的情況下,當你呼叫其產生新的實體addEl()。它可能看起來像這樣:
const instance0 = A.emptyInstance;
instance0._arr // []
instance0._arr.length // 0
const instance1 = instance0.addEl<"whatever">("whatever");
instance1._arr // ["whatever"]
instance1._arr.length // 1
const instance2 = instance1.addEl<number>(42);
instance2._arr // ["whatever", number]
instance2._arr.length // 2
這與您的原始示例沒有太大區別,現在 TypeScript 絕對可以代表這一點。以下是我將如何實作它:
class A<T extends any[]>{
static emptyInstance = new A<[]>([]);
private constructor(public _arr: T) { }
addEl<U>(el: U): A<[...T, U]> {
return new A([...this._arr, el]);
}
}
這里的A類是通用的T,_arr屬性的型別。(請注意,我將其_arr用作引數屬性,因此它既作為實體的屬性存在,又作為建構式的引數存在。)
型別addEl()使用可變元組型別來表明結果將是一個新實體,A其中元組型別T與附加型別的額外元素U(的型別el)類似。雖然您可以只 push()將元素放到現有_arr屬性上并回傳this,但您必須記住在呼叫addEl(). 通過回傳一個新實體,您可以確保這些值是不可變的以匹配型別的不變性。
此版本的代碼適用于方法鏈接,除非您需要它們,否則您不會保留中間實體:
const allAtOnce = A.emptyInstance.addEl(true).addEl(0).addEl(new Date);
// const allAtOnce: A<[boolean, number, Date]>
如果這種不變性重構適用于您的用例,那就太好了!
如果沒有,那么您可能需要放棄讓編譯器跟蹤_arr屬性的確切當前狀態并回退到未知元素的無序陣列,并且任何檢查都只需要在運行時進行。
// fallback ??
class A {
_arr: any[] = []
addEl(el: any) {
this._arr.push(el)
}
}
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/419751.html
標籤:
