在我的許多專案中,我都有一個反復重復的共同模式。
type RequestStatus =
| 'pending'
| 'requesting'
| 'successful'
| 'failed'
type AValue = string | undefined
type OtherValue = number
interface State {
requestStatus: RequestStatus;
aValue?: AValue;
otherValue?: OtherValue;
}
const [requestState, setRequestState] = useState<State>({
requestStatus: 'pending',
aValue: 'aValue',
otherValue: 11
});
const appendToState = (state: Partial<State>) =>
setRequestState(previousState => ({ ...previousState, ...state }));
在這種情況下,我正在獲取值并根據requestStatus和 值更改 UI。
這在我的專案中一遍又一遍地重復,為了減少重復,我正在考慮將所有這些都包裝在一個鉤子中。我的主要問題是處理型別。
這是我的嘗試之一。
export const useExtendedRequestStatus = <T>(state: T) => {
const [requestState, setRequestState] = useState<{ requestStatus: RequestStatus } & T>({
requestStatus: 'pending',
...state,
});
const appendToState = (state: Partial<T>) =>
setRequestState(previousState => ({ ...previousState, ...state }));
return { requestState, setRequestState, appendToState };
};
我會像這樣實作它
const {
requestStatus,
appendToState
} = useExtendedRequestStatus<{ requestStatus: RequestStatus; aValue: AValue }>({
aValue: aValue,
requestStatus: 'successful',
});
它有效,但并不完美。在某些情況下,如果我對鉤子進行靜態型別檢查,我必須重新定義RequestStatus已經在鉤子中定義的型別。我想知道是否有一種方法,RequestStatus在手動型別檢查時仍然會陷入困境,而無需重新定義它。
我對任何想法持開放態度。
uj5u.com熱心網友回復:
您確實T在自定義掛鉤中使用了泛型useExtendedRequestStatus,它描述了您想要使用它的狀態的可能成員。
state但是,由于您在呼叫自定義鉤子時指定引數是T直接型別的,如果您希望它包含一個 initial requestStatus,那么您必須requestStatus在顯式具體型別中也提到這個成員(當然您可以依賴自動型別推斷,但我猜你有理由手動型別檢查)。
您可以輕松地將這個預定義的成員“嵌入”到您的自定義鉤子中,并使其可用于您的引數(對于 相同appendToState),以您已經對您的 inner 完成的非常相似的方式useState<{ requestStatus: RequestStatus } & T>({...}):只需指定您的state引數也是型別T & { requestStatus: RequestStatus }(或正如您在自定義掛鉤中的初始默認值所建議的那樣,T & Partial<{ requestStatus: RequestStatus }>如果requestStatus最初可以省略可能會更好)。這樣,T不再需要包含該requestStatus成員。對appendToState.
interface IRequestStatus {
requestStatus: RequestStatus;
}
export const useExtendedRequestStatus = <T>(
state: T & Partial<IRequestStatus> // Initial state can contain requestStatus, even if not mentioned in concrete T
) => {
const [requestState, setRequestState] = useState<IRequestStatus & T>({
requestStatus: 'pending',
...state,
});
const appendToState = (state: Partial<T & IRequestStatus>) =>
setRequestState((previousState) => ({ ...previousState, ...state }));
return { requestState, setRequestState, appendToState };
};
現在在您的 React 功能組件中,您可以像這樣使用它:
const { requestState, appendToState } = useExtendedRequestStatus<{
//requestStatus: RequestStatus; // Can now be omitted
aValue: AValue;
}>({
aValue: aValue,
requestStatus: 'successful', // Okay
});
requestState.requestStatus; // Okay
appendToState({
requestStatus: 'successful', // Okay
});
演示:https ://stackblitz.com/edit/react-ts-eyyzhg?file=Hello.tsx
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/426105.html
上一篇:在非泛型基類中定義泛型屬性
下一篇:帶有一些引數的通用介面的依賴注入
