Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

293
Views
how to convert Record to another Record with different keys in typescript

I have a function convert, its parameter is an object, the value can be function or an object contains three properties, the type looks like this.

type Input = {
  [K: string]: () => any | { pending: () => any, fulfilled: () => any, rejected: {} => any }
}

I hope can return an object, that the keys will generate by the values, for example:

const result = convert({
  sync() {},
  async: {
    pending() {},
    fulfilled() {},
    rejected() {}
  }
});
// the keys of result
result.sync();
result.asyncPending();
result.asyncFulfilled();
result.asyncRejected();

currently, I know how to generate result by the keys and the string literals

type Result<Input> = {
  [key in keyof Input as `${string & key}Fulfilled`]: any
}

but can't meet my requirement, I google for a long time, but can't found the solution.

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

My proposed solution would look like this:

type Input = {
  [key: string]: { pending: () => any, fulfilled: () => any, rejected: () => any } | (() => any)
}

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

type Result<Input> = {
  [K in keyof Input as Input[K] extends () => any ? K : never]: Input[K]
} & UnionToIntersection<{
  [K in keyof Input]: { 
    [K2 in keyof Input[K] as `${K & string}${Capitalize<K2 & string>}`]: Input[K][K2] 
  }
}[keyof Input]> extends infer O ? { [K in keyof O]: O[K] } : never

function convert<T extends Input>(arg: T): Result<T> {
    return {} as any
}

For each property K of Input where the type is an object we map over the keys in Input[K]. For each key K2 inside Input[K], we rename the key to ${K & string}${Capitalize<K2 & string>} and return the type Input[K][K2]. The resulting mapped object is converted to a union by indexing it with keyof Input.

This union can be converted to an intersection with UnionToIntersection to get all nested keys a level higher.

Now result has the correct type:


const result = convert({
  sync() {},
  async: {
      pending() {},
      fulfilled() {},
      rejected() {}
  }
});
// const result: {
//     sync: () => void;
//     asyncPending: () => void;
//     asyncFulfilled: () => void;
//     asyncRejected: () => void;
// }

result.sync();
result.asyncPending();
result.asyncFulfilled();
result.asyncRejected();

Playground

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!