是否有可能创建一个接口,其属性类型根据另一个属性更改,而不显式地在编译时知道它?

我希望能够根据对象的另一个属性推断对象的属性类型,而不必像Newtype那样声明T。而是声明Newtype并从属性推断T。见下图:

export interface Action {
  type: K;
  payload: K extends "UPDATE_FIVE_DAY"
    ? {
        fiveDayForecast?: FiveDayForecast;
        fiveDayExpiresAt?: Moment;
        fiveDayLocationFor?: Location;
      }
    : K extends "UPDATE_LOADING"
    ? { loading: boolean }
    : K extends "UPDATE_LOCATION"
    ? { location: Location }
    : K extends "UPDATE_SETTINGS"
    ? { settings: Settings }
    : undefined;
}

我遇到的问题是变量K不存在,我可以这样设置它:

export interface Action<K extends 'UPDATE_FIVE_DAY' | 'UPDATE_LOADING' | ...etc
但是,我需要声明action.type的类型,我不一定知道。我想使用如下类型:

我要在通用减速器中使用此操作:

export default (state: State = initialState, action: Action): State => {
  switch (action.type) {
    case "UPDATE_LOADING":
      return {
        ...state,
        loading: action.payload,
      };
  }
});
但是,Return语句会抛出一个类型错误,因为它认为action.payload可能是任何可能的返回类型。这不是真的。


解决方案

我按照@shlang的建议,使用区别对待的联合使其正常工作。

减速机:

export default (state: State = initialState, action: Actions): State => {
  switch (action.type) {
    case "UPDATE_LOADING":
      return {
        ...state,
        loading: action.payload.loading,
      };
   }
});

和操作的类型:

export type Action = {
  type: AllActionTypes;
  payload: Partial<State> | undefined;
};

export type Actions =
  | UpdateFiveDayAction
  | UpdateLoadingAction;


export interface UpdateLoadingAction extends Action {
  type: "UPDATE_LOADING";
  payload: { loading: State["loading"] };
}


export interface UpdateFiveDayAction extends Action {
  type: "UPDATE_FIVE_DAY";
  payload: {
    fiveDayForecast: State["fiveDayForecast"];
    fiveDayExpiresAt: State["fiveDayExpiresAt"];
    fiveDayLocationFor: State["fiveDayLocationFor"];
  };
}

相关文章