首页 > 解决方案 > 打字稿如何键入一个代理它的道具并注入一个道具

问题描述

我有一个辅助函数,它采用函数对象并返回该对象的代理,其函数由注入的第一个 arg 组成。

更好地显示在代码中:-

// example of object
export const selectors = {
  selectA: (state:State) => state.a,
  addToA : (state:State, num:number) => state.a + num
}

// ... in another file my helper fn

import {useSelector} from 'react-redux';

// PROBLEM IS HERE...
export const function bindSelector(obj){
  return new Proxy(obj,{
    get: (main, key, ctx) => {
      const fn = main[key].bind(ctx);

      // always inject store as first prop of fn
      // we get store arg from useSelector higher order (its already properly typed)
      return props => useSelector( store=> fn(store, props) )
    }

  })
}

export default bindSelector(selectors);

所以我使用代理,这样我就不必包含 useSelector,或者在我使用它时将存储参数传递给每个选择器

这个的示例用法是

import selectors from './a';

// now i can just
const a = selectors.selectA(); // give error param missing
const aAnd2 = selectors.addToA(2); // how to tell typescript that this first arg is in fact the 2nd arg :D !.

问题

  1. 如果我键入 bindSelector 以返回相同类型的 (obj),那么我会收到错误,selecte require 1 param因为 typescript 不知道我的代理已经提供了第一个参数来运行。

标签: typescriptgenericsclosurescurrying

解决方案


您可以使用一些映射类型和条件类型将原始对象映射到每个函数少一个参数的新对象:


import { useSelector } from 'react-redux';

type State = {
  a: number
}
// example of object
export const selectors = {
  selectA: (state: State) => state.a,
  addToA: (state: State, num: number) => state.a + num
}

type CurriedFunctionObject<T> = {
  [P in keyof T]: T[P] extends (s: State, ...p: infer P) => infer R ? (...p: P) => R : never
}

export function bindSelector<T extends Record<string, (...a: any) => any>>(obj: T): CurriedFunctionObject<T> {
  return new Proxy(obj, {
    get: (main, key, ctx) => {
      const fn = main[key as keyof T].bind(ctx);

      // always inject store as first prop of fn
      // we get store arg from useSelector higher order (its already properly typed)
      return (args: any[]) => useSelector(store => fn(store, ...args))
    }

  }) as any as CurriedFunctionObject<T>
}

const cSelectors = bindSelector(selectors);
const a = cSelectors.selectA(); // give error param missing
const aAnd2 = cSelectors.addToA(2)

您可以State在条件类型中替换为 any 以使该类型适用于任何状态。


推荐阅读