Typescript:使用泛型将对象映射到另一个对象

Typescript:使用泛型将对象映射到另一个对象,typescript,function,generics,bind,Typescript,Function,Generics,Bind,我正在用typescript构建一个系统,其中有两种对象类型:Actions和ExtendedActions。它们都应该共享相同的属性名,并且每个属性都应该是一个函数 其思想是,系统应该通过采取ExtendedActions并绑定到每个成员函数的第一个参数来自动生成操作 我创建了一个最小的示例(不起作用) 函数createId(){ 返回“测试” } 接口动作{ setName:(名称:字符串)=>void setTitle:(title:string)=>void } /** *Extende

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

其思想是,系统应该通过采取ExtendedActions并绑定到每个成员函数的第一个参数来自动生成操作

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

函数createId(){
返回“测试”
}
接口动作{
setName:(名称:字符串)=>void
setTitle:(title:string)=>void
}
/**
*ExtendedActions与Actions相同,只是
*每个函数都有一个附加的id参数:
*/
类型AddArg=F扩展(…args:inferp)=>inferr
? (id:string,…args:P)=>R
:从不
类型ExtendedActions={
[P in keyof Actions]:AddArg
}
//实例化ExtendedActions。
常量myExtendedActions:ExtendedActions={
setName:(id:string,name:string)=>{
//
},
setTitle:(id:string,title:string)=>{
//
},
}
/**
*(不起作用)通过绑定ExtendedActions的id参数来通用地实例化操作。
*/
函数生成(
extendedActions:TExtendedActions
):触觉{
常量id:string=createId()
返回Object.fromEntries(
Object.keys(extendedActions).map((名称:string)=>{
return[name,extendedActions[name].bind(id)]
})
)作为战术
}
//实例化操作。
const myActions=生成操作(
myExtendedActions
)
当前代码抱怨我无法访问属性extendedActions[name]:
元素隐式具有“any”类型,因为“string”类型的表达式不能用于索引类型“unknown”。在“unknown”类型上未找到具有“string”类型参数的索引签名。TS7053

然而,即使这样做可行,上述方法也不够,因为 fromEntries()只创建一个动态对象,需要将其强制转换到类型TActions中,而不会丢失类型信息

将类型“{[k:string]:***;}”转换为类型“TActions”可能是错误的,因为两种类型都没有足够的重叠。如果这是有意的,请先将表达式转换为“未知”可以使用与“{[k:string]:***;}”无关的任意类型实例化“TActions”。TS2352


有什么方法可以实现这种泛型行为吗?

我并不真正了解需求,但我觉得您更需要组合,而不是继承和泛型。您可以定义ExtendedAction,使其具有类似
构造函数(id:string,action:action){}
的构造函数,前提是action不再是接口。
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
)