打字稿仅部分推断泛型

时间:2021-06-26 15:59:32

标签: typescript typescript-generics

我目前正在尝试编写一个类型化的 React 钩子,但在这样做时遇到了麻烦。我的函数如下所示:

export const useProjectState = <
  GetStateArgs extends any[],
  StateShape,
  Dispatcher
>(
  state: State<GetStateArgs, StateShape, Dispatcher>,
  ...args: GetStateArgs
): [StateShape, Dispatcher] => {
  const [currentState, setCurrentState] = useState<StateShape>(() =>
    state.getState(...args)
  );

  useEffect(() => {
    const update = () => setCurrentState(state.getState(...args));
    state.subscribe(update);
    return () => state.unsubscribe(update);
  }, [state]);

  return [currentState, state.dispatchers];
};

虽然我使用它时,保留了泛型的形状,但不保留它们的类型:

Input type Output type

{ name, author } 是推断的,但不是 { name: string, author: string } 例如。我也尝试从 State 类型中提取泛型:

const useProjectState = <
  CurrentState extends State<any[], any, any>
>(
  state: CurrentState, 
  ...args: CurrentState extends State<infer GetStateArgs, any, any> ? GetStateArgs : never
): [
  CurrentState extends State<any[], infer StateShape, any> ? StateShape : never, 
  CurrentState extends State<any[], any, infer Dispatchers> ? Dispatchers : never
] => {

但是这样不行,类型都变成了unknown

Output with generics extraction through conditional types

我似乎找不到任何方法让它起作用,有人可能知道我做错了什么或让它起作用的方法吗?

这就是 State 的样子:

export interface State<
  GetStateArgs extends any[],
  StateShape,
  Dispatchers
> {
  subscribe: (fn: () => void) => void;
  unsubscribe: (fn: () => void) => void;
  getState: (...args: GetStateArgs) => StateShape;
  forceUpdate: () => void;
  dispatchers: Dispatchers;
}

1 个答案:

答案 0 :(得分:0)

效果很好,你可以在这里试试:TS Playground

链接太长,无法发表评论,所以我创建了答案。