繁体   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