打字稿:使用泛型将对象映射到另一个

时间:2021-04-07 10:00:32

标签: typescript function generics bind

我正在用 typescript 构建一个系统,其中有两种对象类型:ActionsExtendedActions。它们应该共享相同的属性名称,并且每个属性都应该是一个函数。

这个想法是系统应该通过获取 ExtendedActions 并绑定到每个成员函数的第一个参数来自动生成 Actions。

我创建了一个最小的示例(不起作用)。

function createId() {
  return 'test'
}

interface Actions {
  setName: (name: string) => void
  setTitle: (title: string) => void
}

/**
 * ExtendedActions is identical to Actions, except
 * that each function has an additional id parameter:
 */
type AddArg<F> = F extends (...args: infer P) => infer R
  ? (id: string, ...args: P) => R
  : never

type ExtendedActions = {
  [P in keyof Actions]: AddArg<Actions[P]>
}

// Instantiate ExtendedActions.
const myExtendedActions: ExtendedActions = {
  setName: (id: string, name: string) => {
    //
  },
  setTitle: (id: string, title: string) => {
    //
  },
}

/**
 * (Doesn't work) Generically instantiate Actions by binding the id parameter from ExtendedActions.
 */
function generateActions<TExtendedActions, TActions>(
  extendedActions: TExtendedActions
): TActions {
  const id: string = createId()

  return Object.fromEntries(
    Object.keys(extendedActions).map((name: string) => {
      return [name, extendedActions[name].bind(id)]
    })
  ) as TActions
}

// Instantiate Actions.
const myActions = generateActions<ExtendedActions, Actions>(
  myExtendedActions
)

当前代码抱怨我无法访问属性extendedActions[name]: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'. No index signature with a parameter of type 'string' was found on type 'unknown'. TS7053

然而,即使这行得通,上述方法还是不够的,因为 Object.fromEntries() 只是创建了一个动态对象,需要将其强制转换为 TActions 类型,而不会丢失类型信息;

Conversion of type '{ [k: string]: ***; }' to type 'TActions' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. 'TActions' could be instantiated with an arbitrary type which could be unrelated to '{ [k: string]: ***; }'. TS2352

有什么方法可以实现这种通用行为吗?

0 个答案:

没有答案