类型检查对象中已更改的函数签名

Type Checking Changed Function Signature in an Object

问题

我正在为 redux-starter-kit to make it feel more like Vuex. The Github repo is here I'm working on this branch 创建一个包装器。这个项目是一个实验。问题是我无法正确检查这些减速器的类型。

问题

如果你有一个像这样的函数对象。

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

然后它通过另一个函数并带走了第一个参数。你如何保持负载类型检查?

我可以在单个函数上使用泛型来做到这一点,然后对 return

进行类型转换

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

整天胡思乱想之后。我学到了很多关于 TypeScript 类型的知识,哇,它强大而丑陋。我对此还是个新手,所以如果有人有更好的选择或者我有什么误解,请纠正我。

步骤

  1. 删除函数中的第一个参数并将第二个参数移动到第一个位置并保留类型。
  2. 遍历对象并将步骤 1 应用于每个项目。
  3. 我们需要提取我们传递给 IActionPayload<number>
  4. 的类型

第 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。如果它是一个函数,将 args 捕获为 unknown[] 类型的 A 但因为它是一个数组,我们可以说 A[1] 并获取我们的有效负载。所以如果它是一个函数 return type (payload:A[1]) => any else never

第 2 步 - 循环

你可以用这个遍历对象。

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

现在我们需要做第 1 步到 obj[key]

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 所以拉它 else return 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]> }