具有不同值的对象的Typescript副本。推断部分参数

问题描述 投票:0回答:1

我正在尝试创建一个更严格的reducer,它在其中返回您可以使用键入的参数调用的操作。

我创建了最简单的示例,删除了特定于React的内容。

export type TMicroReducer<T extends any[], State = any> = {
  [key: string]: (state: State, ...rest: T) => State;
};

export default function useMicroReducer<T extends any[], State = any>(
  reducers: TMicroReducer<T, State>,
  initialState?: State,
) {
  // This is not the right way to infer the args and map the keys
  const dispatch: {
    [key in keyof typeof reducers]: (...args: T) => void;
  } = {};

  return dispatch;
}

const dispatch = useMicroReducer(
  {
    add: (state, value: number, value2: string) => {
      return state + value;
    },
    subtract: (state, value: number) => {
      return state - value;
    },
  },
  0,
);

我无法使我的派发函数成为强类型。基本上,我期望这个输入/输出:

// input
{
  add: (state: S, value: number, value2: string) => S,
  subtract: (state: S, value: number) => S,
}
// output
{
  add: (value: number, value2: string) => void,
  subtract: (value: number) => void 
}

如何以通用方式实现这一目标?

非常感谢,卡巴斯尔

typescript
1个回答
0
投票

您的实现有几个缺陷:

  1. TMicroReducer级别上,介绍每个化简器参数T的类型。这意味着每个化简器应仅具有一种类型的参数,但事实并非如此。
  2. [useMicroReducer]缺乏用于表示化简器的泛型,这不允许正确地将准确的传递类型推断为reducers

我对解决方案的想法是-我们需要复制由reducers参数指定的对象,并从其中的每个函数中删除第一个参数-状态。为了实现这一点,我使用了实用程序类型Parameters-它返回参数元组,以及自定义实用程序-Tail,它为我们提供了没有第一个元素的元组,因此正是我们所需要的。多亏了Tuple<Parameters>的组成,我能够创建与reducer具有相同参数的函数类型,但没有第一个。

完整的实现(更改了一些命名):

// utility type constructor - remove first element of the array/tuple
type Tail<T extends any[]> = ((...args: T) => void) extends (head: any, ...tail: infer U) => any ? U : never;

// I removed second generic, not needed at this level
type TMicroReducers<State> = {
  [key: string]: (state: State, ...args: any[]) => State;
};

// introduced generic R to allow proper infering
export default function useMicroReducer<State, R extends TMicroReducers<State>>(
  reducers: R,
  initialState?: State,
) {
  const dispatch: {
    [Key in keyof R]: (...x: Tail<Parameters<R[Key]>>) => void
  } = {} as any; // here casting to any as we need to implement real transformation

  return dispatch;
}

const dispatch = useMicroReducer(
  {
    add: (state, value: number, value2: string) => {
      return state + value;
    },
    subtract: (state, value: number) => {
      return state - value;
    },
  },
  0,
);
© www.soinside.com 2019 - 2024. All rights reserved.