【问题标题】:Property that indexes other property in Typescript在 Typescript 中索引其他属性的属性
【发布时间】:2019-06-09 15:03:44
【问题描述】:

我有以下几种:

interface CellsReducer {
    source: number;
    destination: number;
    plan: string;
    duration: number;
    test: []
}

interface BarReducer {
    baz: string;
}

interface AppState {
    cells: CellsReducer;
    bar: BarReducer;
}

我想用以下对象编写一个接口:

interface Props {
    store: keyof AppState;
    field: // AppState[store]
    data: // AppState[store][field]
}

使用泛型对我没有任何帮助。在以下示例中,fieldsnever 类型结束:

type Stores<T> = keyof T;
type Fields<T> = keyof T[Stores<T>];
type Props<TState> = {
    state: Stores<TState>;
    field: Fields<TState>
}

有没有办法做到这一点?

【问题讨论】:

    标签: typescript generics typescript-generics


    【解决方案1】:

    路径中的每个属性都需要不同的类型参数。这允许编译器推断您指定的特定字段:

    type Props<TState, KStore extends keyof TState, KField extends keyof TState[KStore]> = {
        state: KStore;
        field: KField
        data: TState[KStore][KField]
    }
    
    let p: Props<AppState, "cells", "duration"> = {
      state: "cells",
      field: "duration",
      data: 1
    }
    

    你永远不会得到的原因是因为当编译器尝试扩展AppState[keyof AppState]时,它会得到一个联合CellsReducer | BarReducer。由于只有联合的普通成员可以访问,keyof (CellsReducer | BarReducer)never(没有密钥可以访问)。

    额外的参数捕获实际字段,因此如果KStore 是字符串文字类型"cells" keyof AppState["cells"] 将是应用程序状态下该特定字段的键。 KField 的工作原理类似,允许我们正确输入 data

    为避免两次指定 statefield 值,您可以编写一个辅助函数:

    function propertyFactory<TState>() {
      return function <KStore extends keyof TState, KField extends keyof TState[KStore]>(o: Props<TState, KStore, KField>) {
        return o;
      }
    }
    let p = propertyFactory<AppState>()({
      state: "cells",
      field: "duration",
      data: 1
    })
    

    【讨论】:

      【解决方案2】:

      你的意思是:

      interface Props<T, K extends keyof T, V extends keyof T[K]> {
          state: keyof T;
          field: T[K];
          data: T[K][V]
      }
      

      用法:

      const props: Props<AppState, 'cells', 'plan'> = { /* ... */ } ;
      const props: Props<AppState, 'bar', 'baz'> = { /* ... */ } ;
      

      【讨论】:

        猜你喜欢
        • 2017-07-16
        • 1970-01-01
        • 2016-02-23
        • 1970-01-01
        • 1970-01-01
        • 2021-11-25
        • 2023-04-08
        • 2015-11-22
        相关资源
        最近更新 更多