[英]How to set the type of property based on the parameter passed in typescript?
我正在創建一個反應應用程序並使用打字稿。 我想要一個具有多個屬性的 globalState。 我還需要使用useReducer
。 我為reducer
函數的action
創建了一個接口。 該接口接受一個參數N
,它是動作的name
。 現在我想根據傳遞的N
參數設置data
類型。
我幾乎使用三元運算符創建了它。
export interface IGlobalState {
loading: boolean;
userData: IUserData;
}
interface IUserData {
loggedIn: boolean;
name: string;
}
type GlobalStateActionNames = "setLoading" | "setUserData"
export interface IGlobalStateAction<N extends GlobalStateActionNames = GlobalStateActionNames> {
data: N extends "setLoading"
? boolean
: N extends "setUserData"
? IUserData
: any;
name: N;
}
export const GlobalStateReducer = (
state: IGlobalState,
{name, data}: IGlobalStateAction
): IGlobalState => {
switch(name){
case "setLoading": return {...state, loading: data};
default: return state;
}
};
只有一個問題。 reducer
的data
參數將擴展所有可能是數據值的類型。 因此,當我將loading
設置為data
它會出錯。
輸入
'boolean | IUserData'
'boolean | IUserData'
不可分配給類型'boolean'
我有兩個問題。
注意:我知道我可以通過使用case "setLoading": return {...state, loading: data as boolean};
來解決這個問題case "setLoading": return {...state, loading: data as boolean};
. 但是 globalState 將有許多其他道具。 所以我不想對所有的價值觀都這樣。
問題是您的IGlobalStateAction
,要根據需要使用它,您需要在內部傳遞N
泛型,因為這是有條件工作的唯一方法。 由於您無法確定將哪個 action 傳遞給 reducer,因此無法在此級別傳遞N
您可以通過保護此類型或將其更改為標准聯合來解決該問題,它可能不太通用,但無需任何條件類型即可工作。
// pay attention, type is now simple union
export type IGlobalStateAction =
| {
name: "setLoading",
data: boolean
}
| {
name: 'setUserData',
data: IUserData
}
export const GlobalStateReducer = (
state: IGlobalState,
action: IGlobalStateAction
): IGlobalState => {
switch(action.name){
case "setLoading": return {...state, loading: action.data}; // correctly infers bool
default: return state;
}
};
第二種解決方案是,如果你想離開你的條件類型 - 有類型保護。 考慮:
// here your original type
// type guard narrowing the type
const isActionWithName = <N extends GlobalStateActionNames>
(a: IGlobalStateAction, n: N): a is IGlobalStateAction<N> => a.name === n;
export const GlobalStateReducer = (
state: IGlobalState,
action: IGlobalStateAction
): IGlobalState => {
// using type guard
if (isActionWithName(action, 'setLoading')) {
return {...state, loading: action.data};
}
return state;
};
這里發生了什么 - isActionWithName
函數檢查名稱並將正確的泛型放入IGlobalStateAction
(這可以在這里發現 - a is IGlobalStateAction<N>
)。 在檢查時,我們可以確定它的確切名稱,以及它如何影響data
類型。
對不起,我是通過電話做的,但你可以查看我的回購,我有你想要的東西
https://github.com/EnetoJara/-eneto-react-init
export const DO_SOME = ”DO_SOME”;
export type DO_SOME = typeof DO_SOME;
interface AppAction<T,P> {
type: T;
payload?: P;
}
export function actionCreator(someParam; ParamType): AppAction<DO_SOME, ParamType> {
return {
type: DO_SOME,
payload: someParam
}
還記得你可以對他們的功能做這樣的事情
function nameOfFunction<T, R> (param: T): Promise<R> {
return httpCal(whatever).then((res: R) => red);
T = 類型 R = 結果遺傳學這就是他們的稱呼
然后只是為了使用它讓我們想象一下
const a = nameOfFunction<UserModel, HttpCode> (user).then((res: HttpCode)=>res);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.