打字稿如何键入代理其道具并注入道具的代理

时间:2019-10-28 12:55:15

标签: typescript generics closures currying

我有一个辅助函数,该函数接受和函数对象,并返回该对象的代理,该对象的功能由注入的第一个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);

所以我使用Proxy,这样我就不必包括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的错误。

1 个答案:

答案 0 :(得分:1)

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


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)

Play

您可以将State替换为条件类型中的任何一种,以使该类型适用于任何状态。