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

111
Views
Need help to convert typescript helper

I have a helper I'm exporting and importing into multiple files which is working fine, however I want to change it slightly and I'm struggling to figure this one out:

// utils.ts
export enum RequestTypes {
  Request,
  Success,
  Failure,
}

type CombineEnums<P, C> = {
  [KP in keyof P]: {
    [KC in keyof C]: KP extends string ? KC extends string ? `${KP}${KC}` : never : never;
  };
};

export function createActions <P, C>(actionTypes: P, requestTypes: C): CombineEnums<P, C> {
  const result: any = {};
  for (const keyP of Object.keys(actionTypes)) {
    result[keyP] = {};
    for (const keyC of Object.keys(requestTypes)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }
  return result;
}

Now in another file I'm importing the createActions method & RequestTypes and using it like so:

// module.ts
import { createActions, RequestTypes } from './utils.ts';
enum Actions {
   Find,
   Create
}
const actions = createActions(Actions, RequestTypes);
// actions.Find.Request -> 'FindRequest'
// actions.Find.Success -> 'FindSuccess'
// actions.Create.Failure -> 'CreateFailure'

This all works fine, however RequestTypes will rarely change, i want to make it an optional argument, but still able to pass through other RequestTypes if needed.

So idealy by default I'd like the above solution but the usage will be:

const actions = createActions(Actions) with the same output.

And if need be, pass through different RequestTypes:

enum TabRequests {
   Open,
   Close
}
enum TabActions {
   Tab
}
const actions = createActions(TabActions, TabRequests);
// actions.Tab.Open -> 'TabOpen'
// actions.Tab.Close -> 'TabClose'

I've tried everything i can think of but can't seem to figure out the typescript side of this!

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

0

You can use typescript overload signatures, also see the playground:

// signature for only one argument
export function createActions <P>(actionTypes: P): CombineEnums<P, typeof RequestTypes>;

// signature for two arguments
export function createActions <P, C>(actionTypes: P, requestTypes: C): CombineEnums<P, C>;

// actual implementation with default value for second argument
export function createActions <P>(actionTypes: P, requestTypes: any = RequestTypes): CombineEnums<P, any> {
  const result: any = {};
  for (const keyP of Object.keys(actionTypes)) {
    result[keyP] = {};
    for (const keyC of Object.keys(requestTypes)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }
  return result;
}

// If you want you could also use the following line as implementation signature
// export function createActions <P, C>(actionTypes: P, requestTypes: C | typeof RequestTypes = RequestTypes): CombineEnums<P, C | typeof RequestTypes> {


// Now you can use both signatures, typesafe.
const actionsWithRequestTypeArgument = createActions(Actions, RequestTypes);
const actionsWithoutRequestTypeArgument = createActions(Actions);
about 4 years ago · Juan Pablo Isaza Report

0

Here's how you can use the overloaded function from the other answer in a separate module:

TS Playground link

// utils.ts

type StringEnum = Record<string, string>;

export type NestedCombinedStringEnum<
  P extends StringEnum,
  C extends StringEnum,
> = {
  [KP in keyof P]: {
    [KC in keyof C]: KP extends string ? KC extends string ? `${KP}${KC}` : never : never;
  };
};

export function nestAndCombineStringEnums <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild: C): NestedCombinedStringEnum<P, C> {
  const result: any = {};

  for (const keyP of Object.keys(enumParent)) {
    result[keyP] = {};
    for (const keyC of Object.keys(enumChild)) {
      result[keyP][keyC] = `${keyP}${keyC}`;
    }
  }

  return result;
}

export enum RequestType {
  Request = 'Request',
  Success = 'Success',
  Failure = 'Failure',
}

export function createActions <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild: C): NestedCombinedStringEnum<P, C>;
export function createActions <P extends StringEnum>(enumParent: P): NestedCombinedStringEnum<P, typeof RequestType>;
export function createActions <
  P extends StringEnum,
  C extends StringEnum,
>(enumParent: P, enumChild?: C) {
  return nestAndCombineStringEnums(enumParent, enumChild ?? RequestType);
}

// module.ts

import {createActions, RequestType} from './utils.ts';

enum ActionType {
  Find = 'Find',
  Update = 'Update',
  Create = 'Create',
}

const actions = createActions(ActionType); // same as createActions(ActionType, RequestType);
console.log(actions.Create.Success); // "CreateSuccess"
console.log(actions); // the expected result object in your question

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!