打字稿多类型映射

Typescript multiple type mapping

我想像这样做一些类型映射:

有些模块带有idactions,我想合并所有的动作方法并重新映射其方法名称添加${id}/前缀,示例代码在这里:

const m1 = {
  id: 'm1',
  actions: {
    down(id: string) {
      return true;
    },

    up(n: number) {
      return 0;
    }
  }
}

const m2 = {    
  id: 'm2',
  actions: {
    play(id: string) {
      return true;
    },

    go(n: number) {
      return 0;
    }
  }
}

type MyModule = ??

// should return :
// MyModule = {
//   'm1/down': (id: string) => boolean,
//   'm1/up': (n: number) => number;
//   'm2/play': (id: string) => boolean;
//   'm2/go': (n: number) => number;
// }

Playground

这在打字稿中可能吗?

您可以在较新版本的 Typescript 中使用映射类型和模板文字类型来执行此操作:

type ModuleDefnition = {
  id: string,
  actions: Record<string, (...a: any[]) => any>
}
type Module<T extends ModuleDefnition> = {} & {
  [P in keyof T['actions'] & string as `${T['id']}/${P}`]: T['actions'][P]
}

type MyModule = Module<typeof m1> & Module<typeof m2>

Playground Link

模块定义的唯一变化是id你需要确保你有一个字符串文字类型

如果您有未知数量的模块或者您想使用函数创建模块,您也可以使用 UnionToIntersection(来自 )。


type DistributeModule<T extends ModuleDefnition> = T extends T ? Module<T> : never;

type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

function merge<T extends ModuleDefnition[]>(...a: T):UnionToIntersection<DistributeModule<T[number]>> {
  return null!;
}

let myModule = merge(m1, m2)

Playground Link