1

I want to do some type mapping like this:

There are some modules with id and actions, I want to combine all actions method and remap its method name adding ${id}/ prefix, sample code is here:

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

Is this possible in typescript?

1 Answer 1

1

You can do this using mapped types and template literal types in newer versions of 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

The only change to the module definitions is that for id you need to make sure you have a string literal type

You can also use UnionToIntersection (from here) if you have an unknown number of modules or you want to create the modules using a function.


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

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome answer! I tried [P in `${T['id']}/keyof T['actions']`]: T['actions'][P] and stucked here, never thought can use as here. And for the const id, UnionToIntersection, really resolved my problem, learned a lot from your answer, really thx :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.