簡體   English   中英

如何根據typescript中傳入的參數設置屬性的類型?

[英]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;
    }
}; 

只有一個問題。 reducerdata參數將擴展所有可能是數據值的類型。 因此,當我將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM