問題是
。我有兩個還原器,它們對兩個包含點的不同陣列使用完全相同的邏輯。一個陣列只能有單一型別的點;這些型別是A和B。我想創建一個還原器,它接受一個型別為A或型別為B的點陣列,然后回傳一個相同型別的陣列。
當我嘗試編譯下面的代碼時,我得到了這樣的錯誤:
當我嘗試編譯下面的代碼時,我得到了這樣的錯誤。
Argument of type 'Partial< A>| Partial<B>'不能分配給引數of型別'Partial<T>'。
型別 'Partial<A>'不能被分配到型別'Partial<T>'。
我怎樣才能解決這個問題?
有問題的代碼
enum Category {
A,
B
}
介面A {
readonly category: Category.A。
}
介面B {
readonly category: Category.B。
}
Category =
const genericReducer = < T extends A | B>/span>(
狀態。我的狀態。
行動。Actions,
點。T[],
類別。類別
): T[] => {
switch (action.type) {
case POINT_UPDATED: {
if (action.payload.category !== category) return points;
return updateItemInArray(point, action.payload.id, (stpt) => {
return updateObject(stpt, action.payload.newValues);
});
}
默認情況下。
回傳點數。
}
};
ArrayUtils.updateObject
。作為參考,這里是updateObject函式:
static updateObject = <T>(oldObject: T, newValues: Partial<T> ) => /span> {
//封裝傳遞一個新物件作為第一個引數的想法。
//向Object.assign確保我們正確地復制資料而不是變異。
return Object.assign({}, oldObject, newValues)。
};
updateItemInArray函式
。static updateItemInArray = <T> (array: T[], itemId: string, updateItemCallback: (item: T) => T): T[] => {
const updatedItems = array.map((item) => {
if (item.id !== itemId) {
//由于我們只想更新一個專案,所以保留其他所有專案的現狀。
return item。
}
//使用提供的回呼來創建一個更新的專案。
const updatedItem = updateItemCallback(item)。
return updatedItem;
});
return updatedItems;
};
編輯 #1
這里有一個CodeSandbox的鏈接,是我根據Linda Paiste的回答進行的最新嘗試。在這個時候,仍然有一個分配給型別Partial<T>的問題。
uj5u.com熱心網友回復:
我開始嘗試填補你的代碼的缺失部分,以便找到問題所在。 這樣做,很明顯,問題出在你的Action型別中(正如@Alex Chashin所建議的)。
我知道Actions有一個type,需要包括POINT_UPDATED。 它也有一個payload。 這個payload包括一個id,一個category,和一些newValues。
type Actions = {
type: typeof POINT_UPDATED;
payload: {
id: string;
category: Category;
newValues: ????;
}
什么是newValues? 根據updateObject的簽名,我們知道它應該是Partial<T>/code>。 但是Actions不知道T是什么。
我猜測你的代碼使用了類似于newValues的東西。A | B;,這給了我你發布的錯誤。 這還不夠具體。 僅僅知道我們的新值是"A或B"還不夠。 updateObject說,如果T是A,那么newValues必須是A;如果T是B,那么newValues必須是B。
因此,你的Actions需要是一個通用型別。
type Actions< T> = {
type: typeof POINT_UPDATED;
payload: {
id: string;
category: Category;
newValues: Partial<T> 。
}
}
const genericReducer = <T extends A | B>(
狀態。MyState,
行動。Actions<T>。
點。T[],
類別。類別
): T[]
...
<解釋一下
我在你的updateItemInArray上看到一個錯誤,當試圖訪問item.id時:
屬性'id'在型別'T'上不存在
。
你需要細化T的型別,使其知道id屬性:
const updateItemInArray = < T extends {id: string}>(
這樣做會在你的genericReducer中引起新的錯誤,因為你說過T必須有一個category,但你沒有說它必須有一個id。 我們可以用以下方法來解決這個問題:
const genericReducer = <。 T extends (A | B) & {id。 string}>(
這與
相同const genericReducer = < T extends {id: string; category: Category}> (
盡管實際上,你似乎從來沒有在你的點category上看過T[]。 所以你真正需要的是:
const genericReducer = < T extends {id: string}>(
編輯:
編輯:
編輯:
編輯
編輯:
你在修改后的代碼中得到的錯誤,說實話真的很蠢。 技術上 T 擴展一個帶有{elevation: number}的型別。 因此,有可能需要一個更具體的型別版本,如{elevation: 99}。 在這種特殊情況下,{elevation: number}將不能被分配給Partial<{elevation: 99}>。
至少我認為這就是問題所在。 然而,我的第一次修復并沒有奏效。 我試著改進了Actions的型別,使elevation的屬性必須與T的屬性相匹配。
type Payload<T extends A_or_B> ={
[ActionTypes.FETCH_SUCCEED] 。{
id: string;
elevation: T['elevation'] 。
timestamp: 數字。
};
...
但是我仍然得到一個錯誤,所以現在我徹底困惑了。
型別為
的引數。{ elevation: T["elevation"]; }不能分配給型別為Partial<T>
我真的無法解釋這個問題。
你可能要做一個斷言來代替。(不要理會上面的修正)。
return updateObject<{elevation: number}>(stpt, {
elevation: action.payload.elevation。
}) as T。
我們通過將該函式的通用T設定為{elevation: number}來避免在updateObject函式中的錯誤。stpt(型別T)和{elevation: number}都可以被分配給該型別。
但是現在updateObject函式的回傳型別是{elevation: number}而不是T。 所以我們需要斷言為T,以便改變型別。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/330172.html
標籤:
