是否可以创建一个具有基于另一个属性更改的属性类型的接口,而无需在编译时明确知道它?

Posted

技术标签:

【中文标题】是否可以创建一个具有基于另一个属性更改的属性类型的接口,而无需在编译时明确知道它?【英文标题】:Is it possible to create an Interface with a property type which changes based on another property, without explicity knowing it on compile? 【发布时间】:2020-07-20 05:49:07 【问题描述】:

我希望能够根据对象的另一个属性推断对象的属性类型,而不必像 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 可能是任何可能的返回类型。这不是真的。

【问题讨论】:

你可以使用discriminated-unions,另见official redux dosc Conditional types 在这里可能有用。 @OSH 正如您在我的示例中看到的那样,条件类型要求我在调用时定义类型,并且 TS 仍然假设 Payload 可以是任何类型。 @Shlang 已经使用可区分的联合管理了一个工作原型,这比我想要的开销要多一些,但可以工作。谢谢。 【参考方案1】:

按照@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"];
  ;

【讨论】:

以上是关于是否可以创建一个具有基于另一个属性更改的属性类型的接口,而无需在编译时明确知道它?的主要内容,如果未能解决你的问题,请参考以下文章

在RealmSwift中,当两个对象中的每一个都具有另一个对象的属性时,是否创建了一个保留周期?

使变量指向另一个变量

是否可以从另一个单独的 .NET AppDomain 更改 .NET AppDomain 中的字符串属性的值

检查是不是已创建另一个具有相同名称的 DataFrame。错误:“str”对象没有属性“append”

在 coredata 中添加实体和另一个实体的属性之间的关系

属性参数类型作为另一个属性