类型检查对象中更改的功能签名

时间:2019-09-05 16:49:33

标签: typescript typechecking

问题

我正在为redux-starter-kit创建一个包装器,以使其看起来更像Vuex。 Github仓库是here,我正在研究这个branch。这个项目是一个实验。问题是我无法正确检查这些减速器的类型。

问题

如果您有类似函数的对象。

const reducers = {
  addCounter(state:IState, payload:IActionPayload<number>):void {
    state.counter += payload.payload;
  }
}

它通过另一个函数并带走了第一个参数。您如何保持有效载荷的类型检查?

我可以在单个函数上使用泛型来执行此操作,并类型化返回

enter image description here

我不确定如何为对象中的每个函数动态地执行此操作。

1 个答案:

答案 0 :(得分:0)

整天黑客入侵后。我从TypeScript类型中学到了很多东西,哇,它功能强大又难看。我对此还是很陌生,因此,如果有人有更好的选择,或者如果我误解了某些东西,请纠正我。

步骤

  1. 删除函数中的第一个参数,并在保留类型的同时将第二个参数移到第一个位置。
  2. 将对象放在一个对象上,然后将第1步应用于每个项目。
  3. 我们将需要提取要传递给IActionPayload<number>的类型

步骤1-功能更改

// Formats a Reducer Function to remove state and place the 
// payload parameter as the first parameter
type ReducerToAction <R> = R extends (...args: infer A) => any ? (payload:A[1]) => any : never

它可以工作,但肯定很难看。 全部与conditionals有关。如果它是一个函数,则将unknown[]类型的args捕获为A,但是由于它是一个数组,我们可以说A[1]并获取有效载荷。因此,如果它是一个函数返回类型(payload:A[1]) => any否则为never

第2步-循环

您可以用它来遍历对象。

type loop<obj> = { [key in keyof obj]: obj[key] }

现在我们需要对obj[key]进行步骤1

type loop<obj> = { [key in keyof obj]: ReducerToAction<obj[key]> }

所以看起来像这样。

type ReducersToActions<R> = { [K in keyof R]: ReducerToAction<R[K]> }

步骤3-提取IActionPayload<number>类型

如果您提供type这样的处理方式。

type IActionPayload <T> = { type: string, payload: T }

似乎您可以访问密钥。因此,如果我们也将其置于条件中,则可以从对象中拉出单个键。

type PullPayloadType<P> = P extends IActionPayload<any> ? P['payload'] : never

应该用英语说出它是否为IActionPayload类型,我们知道它具有密钥payload,因此拉动它会返回never

结果

有了这个,我们将需要更新其他类型以使用它,这将为您提供以下内容。

// Action Structure
type IActionPayload <T> = { type: string, payload: T }
// Reducers object structure
type IReduces = { [key:string] : (state:any, payload:IActionPayload<any>) => any }
// Gets the Payload type from an object that is of type IActionPayload
type PullPayloadType<P> = P extends IActionPayload<any> ? P['payload'] : never
// Formats a Reducer Function to remove state and place the payload parameter as the first parameter
type ReducerToAction<R> = R extends (...args: infer A) => any ? (payload:PullPayloadType<A[1]>) => any : never
// Formats Reducer Functions in a object that matches the type IReduces
type ReducersToActions<R extends IReduces> = { [K in keyof R]: ReducerToAction<R[K]> }